boss
boss

Reputation: 1606

How I can change the event as a different method in c#

I need to separate my event as a different method.. But I am using TaskCompletionSource and don't know how can i do that?

Here is my code

    public Task<byte[]> Download(DocumentProfile profile)
    {

        var tcs = new TaskCompletionSource<byte[]>();


        service.DownloadLastVersionCompleted += (sender, args) =>
        {
                if (args.Error != null)
                    tcs.TrySetResult(null);
                if (args.Result != null)
                    tcs.TrySetResult(args.Result);
                else
                    tcs.TrySetResult(new byte[0]);

            };

        service.DownloadLastVersionAsync(profile);
        return tcs.Task;
    }

and I want to do like this

public Task<byte[]> Download(DocumentProfile profile)
{
     var tcs = new TaskCompletionSource<byte[]>();


     service.DownloadLastVersionCompleted+=OnDownloadCompleted;
     service.DownloadLastVersionAsync(profile);

     return tcs.Task;
}


private void OnDownloadCompleted(object sender, DownloadLastVersionCompletedEventArgs e)
{
    .....
}

but here is the problem, how i can return task with that kind of different method. Sometimes I have exception because when I downloaded because of this kind of event, as I search, recommended to separate this event..

I hope its clear..

Upvotes: 1

Views: 53

Answers (1)

Marc Gravell
Marc Gravell

Reputation: 1062520

What you have here is a captured variable (tcs), which the compiler implements using a compiler-generated capture-context class. You can implement the same thing (or something similar) manually:

public Task<byte[]> Download(DocumentProfile profile)
{
    var state = new DownloadState();

    service.DownloadLastVersionCompleted += state.OnDownloadCompleted;
    service.DownloadLastVersionAsync(profile);

    return state.Task;
}
class DownloadState
{
    private TaskCompletionSource<byte[]> tcs = new TaskCompletionSource<byte[]>();
    public Task<byte[]> Task {  get { return tcs.Task; } }
    public void OnDownloadCompleted(
         object sender, DownloadLastVersionCompletedEventArgs args)
    {
        if (args.Error != null)
            tcs.TrySetResult(null);
        if (args.Result != null)
            tcs.TrySetResult(args.Result);
        else
            tcs.TrySetResult(new byte[0]);
    }
}

As an advisory: I am concerned that you never remove the event subscription on service; this could have nasty side-effects if service is re-used / kept around.

Note that sometimes you get to pass in some context to an asynchronous method, in which case you can cheat, for example:

public Task<byte[]> Download(DocumentProfile profile)
{
    var tcs = new TaskCompletionSource<byte[]>();

    service.DownloadLastVersionCompleted += OnDownloadCompleted;
    service.DownloadLastVersionAsync(profile, state: tcs);

    return tcs.Task;
}
private void OnDownloadCompleted(
    object sender, DownloadLastVersionCompletedEventArgs args)
{
    var tcs = (TaskCompletionSource<byte[]>)args.State;
    if (args.Error != null)
        tcs.TrySetResult(null);
    if (args.Result != null)
        tcs.TrySetResult(args.Result);
    else
        tcs.TrySetResult(new byte[0]);
}

Upvotes: 1

Related Questions