I'm writing a PCL that uses an HttpClient
to go visit a few sites and extract data from them. My initial code looked like this:
public static class Download
{
public async static Task<byte[]> FromYouTubeAsync(string videoUri)
{
using (var client = new HttpClient())
{
string source = await client
.GetStringAsync(videoUri);
// get links...
return await client
.GetByteArrayAsync(links.First());
}
}
}
I realized, however, that this would be a waste of resources if the user of my library already had a HttpClient
in hand. For example:
// Caller code
using (var client = new HttpClient())
{
// Do some work with client
byte[] bytes = await Download.FromYouTubeAsync("some://uri"); // A second HttpClient is created here, wasting resources and time...
// Do some work with client and bytes
}
One solution could be to add an overload taking an HttpClient
as a parameter, but what if the user wanted to use a WebClient
instead? Or an HttpWebRequest
? Or some other kind of client that wasn't availsble in the PCL?
My solution
I decided to take delegate parameters to get the page source and to download the file based on the URI. My code now looks like this:
public static class Download
{
public async static Task<byte[]> FromYouTubeAsync(string videoUri)
{
using (var client = new HttpClient())
{
return await FromYouTubeAsync(
() => client
.GetStringAsync(videoUri),
uri => client
.GetByteArrayAsync(uri));
}
}
public async static Task<byte[]> FromYouTubeAsync(
Func<Task<string>> sourceFactory, Func<string, Task<byte[]>> downloadFactory)
{
string source = await sourceFactory();
// get links...
return await downloadFactory(links.First());
}
}
The problem
Hm. Wait, what if the caller is using a client that doesn't support async
, like HttpWebRequest
? Better add another overload taking a Func<string>
and a Func<string, byte[]>
. What if s/he wants to make the first call synchronous, but the second call async
? Or vice versa? OK, just add 2 more overloads. Wait, what if the caller wants the whole operation to be synchronous? Let's go add 4 Download.FromYouTube
overloads wrapping each of the async
methods. Whoops, it turns out we need to visit another page of YouTube in case the video's signature is encrypted! Sure, let's go add 8 mor-
I think you can see where this is going. How do I maintain this flexibility without scaring the user away when Visual Studio says that there are 17 different overloads for this method?