7

I have a synchronous, generic method that looks like this

public TResponse Execute<TResponse>(Request request) where TResponse : Response
{
   return (TResponse) proxy.ExecuteRequest(request);

the proxy is a WCF service reference

It just has one method that takes a request and returns a response. But it is used by passing derived requests and returning derived responses. As you can see above the wrapper method is casting the response to the derived type specified by the generic parameter (TResponse).

You call the method with derived requests and responses

e.g.

Execute<GetSomeDataResponse>(new GetSomeDataRequest());

I am now generating an async service reference so can make use of Tasks

So I would like a method that looks like this

public Task<TResponse> ExecuteAsync<TResponse>(Request request) where TResponse : Response
{
    // need to cast to a Task<TResponse>
    return proxy.ExecuteRequestAsync(request

that can be called like this

Task<GetSomeDataResponse> res = ExecuteAsync<GetSomeDataResponse>(new GetSomeDataRequest());

So I need a way to cast the Task<Response> to a Task<TResponse>

I've been reading this which seems kind of the opposite of what I need, but cant quite figure out how to bend it to my use case

How to convert a Task<TDerived> to a Task<TBase>?

any ideas?

Community
  • 1
  • 1
ChrisCa
  • 10,876
  • 22
  • 81
  • 118
  • Well, you can always just `return (TDerived)(await ExecuteRequestAsync(request));`. – Luaan May 13 '16 at 15:17
  • @Luaan unfortunately ExecuteRequestAsync is not an async method in the .net 4.5 sense - it just returns a Task . it doesnt have async keyword in it's signature (it generated by svcutil so I cant change that) – ChrisCa May 13 '16 at 15:24
  • 1
    @ChrisCa ExecuteRequestAsync does not need any async keyword, your ExecuteAsync does. – Evk May 13 '16 at 15:25
  • @Luaan I tried this line : return (TResponse)(await proxy.ExecuteRequestAsync(request)); but compiler says "the await operator can only be used with an async method, consider adding the async keyword etc etc" – ChrisCa May 13 '16 at 15:29
  • @Luaan sorry - i was being dumb - you are right – ChrisCa May 13 '16 at 15:42

1 Answers1

3

Easy way is use async\await pattern:

 public static async Task<TResponse> ExecuteAsync<TResponse>(Request request) where TResponse : Response {
    var response = await proxy.ExecuteRequestAsync(request);
    return (TResponse) response;
 }

A bit more complicated (taken from your linked question) is to use TaskCompletionSource:

public static Task<TResponse> ExecuteAsync2<TResponse>(Request request) where TResponse : Response {
    var tcs = new TaskCompletionSource<TResponse>();
    proxy.ExecuteRequestAsync(request).ContinueWith(t => {
        if (t.IsFaulted)
            tcs.TrySetException(t.Exception.InnerExceptions);
        else if (t.IsCanceled)
            tcs.TrySetCanceled();
        else
            tcs.TrySetResult((TResponse) t.Result);
        }, TaskContinuationOptions.ExecuteSynchronously);
    return tcs.Task;
}
Evk
  • 98,527
  • 8
  • 141
  • 191