It sounds like you're asking about best practices for implementing a class which exposes methods that have asynchronous versions similar to how WebClient does?
It's worth noting that there's two patterns typically used in the .NET framework for classes that support asynchronous usage. For example, you'll typically see classes like Stream that expose BeginRead and EndRead. These use IAsyncResult and tend to be more complicated to use. (Overview on MSDN)
Then later on they came up with the event-based async pattern such as the one used by WebClient where you have a DownloadString/DownloadStringAsync method and a corresponding DownloadStringCompleted event. This is easier to work with for simple cases but isn't as flexible as the Begin/End pattern in my opinion.
So in your example, you have two overloaded methods. In this case I would simply design them such that the method with fewer parameters defers to the method with more parameters passing default values or nulls as needed. You can have multiple overloads of Download/DownloadAsync but you can only have one DownloadCompleted event which is fine.
Here's a very basic implementation. Notice that the only method really doing any work is one synchronous Download method. It's also important to note that this isn't the most efficient way of doing it either. If you wanted to take advantage of the async IO features of HttpWebRequest and such, this example would get complicated quickly. There's also an overly complex Async Operation pattern that I never liked one bit.
class Downloader {
public void Download(string url, string localPath) {
if (localPath == null) {
localPath = Environment.CurrentDirectory;
}
// implement blocking download code
}
public void Download(string url) {
Download(url, null);
}
public void DownloadAsync(string url, string localPath) {
ThreadPool.QueueUserWorkItem( state => {
// call the sync version using your favorite
// threading api (threadpool, tasks, delegate.begininvoke, etc)
Download(url, localPath);
// synchronizationcontext lets us raise the event back on
// the UI thread without worrying about winforms vs wpf, etc
SynchronizationContext.Current.Post( OnDownloadCompleted, null );
});
}
public void DownloadAsync(string url) {
DownloadAsync(url, null);
}
private void OnDownloadCompleted(object state) {
var handler = DownloadCompleted;
if (handler != null) {
handler(this, EventArgs.Empty);
}
}
public event EventHandler DownloadCompleted;
}