Question

I would like to create a delegate and a method that can be used to call any number of Web services that my application requires:

Example:

public DateCheckResponseGetDate(DateCheckRequest requestParameters)
{
    delegate object WebMethodToCall(object methodObject);

    WebMethodToCall getTheDate = new WebMethodToCall(WebServices.GetTheDate);

    return (DateCheckResponse)CallWebMethod(getTheDate , requestParameters);
}

public TimeCheckResponse GetTime(TimeCheckRequest requestParameters)
{
    delegate object WebMethodToCall(object methodObject);

    WebMethodToCall getTheTime = new WebMethodToCall(WebServices.GetTheTime);

    return (TimeCheckResponse)CallWebMethod(getTheTime, requestParameters);
}

private object CallWebMethod(WebMethodToCall method, object methodObject)
{
    return method(methodObject);
}

But, unfortunately, when I try to compile, I get these errors:

No overload for 'GetTheDate' matches delegate 'WebMethodToCall' No overload for 'GetTheTime' matches delegate 'WebMethodToCall'

It seems like the delegate should work.

WebServices.GetTheDate and WebServices.GetTheTime both take a single parameter (DateCheckRequest and TimeCheckRequest, respectively) and both return a value.

So doesn't the delegate match the signature of the two web methods? (both accept and return types derived from object).

Is it possible to use the object type to make a very reusable delegate in .NET 2.0?

Was it helpful?

Solution

I suggest you use a generic delegate such as Func<T, TResult>:

public DateCheckResponseGetDate(DateCheckRequest requestParameters)
{
    // Split declaration/assignment just to avoid wrapping
    Func<DateCheckRequest, DateCheckResponse> method;
    method = WebServices.GetTheDate;
    return CallWebMethod(method, requestParameters);
}

You'd then make CallWebMethod generic too:

public TResponse CallWebMethod<TRequest, TResponse>
    (Func<TRequest, TResponse> method, TRequest request)
{
    // Whatever you do in here.
}

OTHER TIPS

I'd suggest you change your code to something like:


public DateCheckResponseGetDate(DateCheckRequest requestParameters)
{
    Func<DateCheckRequest, DateCheckResponse> getTheDate = new Func<DateCheckRequest, DateCheckResponse>(WebServices.GetTheDate);

    return CallWebMethod(getTheDate , requestParameters);
}

//DEFINE CallWebMethod ADEQUATELY!
public T CallWebMethod<T,U> (Func<T,U> webMethod, U arg)
{
    return webMethod(arg);
}

This way you can avoid all of the ugly downcasting :)

I worked it out thanks to the comments here.

private delegate object WebMethodToCall<T>(T methodObject);

public DateCheckResponseGetDate(DateCheckRequest requestParameters)
{
    WebMethodToCall<DateCheckRequest> getTheDate = new WebMethodToCall<DateCheckRequest>(WebServices.GetTheDate);

    return CallWebMethod<DateCheckResponse, DateCheckRequest>(getTheDate, requestParameters);
}

public TimeCheckResponse GetTime(TimeCheckRequest requestParameters)
{
    WebMethodToCall<TimeCheckRequest> getTheTime = new WebMethodToCall<TimeCheckRequest>(WebServices.GetTheTime);

    return CallWebMethod<TimeCheckResponse, TimeCheckRequest>(getTheTime, requestParameters);
}

private T CallWebMethod<T, U>(WebMethodToCall<U> method, U methodObject)
{
    return (T)method(methodObject);
}

Yes, but you'd have to rewrite WebServices.GetTheData and GetTheTime to take objects, or provide overloads that take objects.

This is because you can't upcast objects in .NET implicitly. In other words, you can do this:

TimeCheckRequest myTimeCheckRequest;
object foo = myTimeCheckRequest;

but you can't do this:

object myTimeCheckRequest;
TimeCheckRequest  foo = myTimeCheckRequest;

You may define Func as:

public delegate TResult Func<T, TResult>(T arg);

This definition requires nothing that's not available in .NET 2.0 and added to the snipped I've posted above solves your problem :)

UPDATE: May no longer be valid? Dunno, I've done this in C# 2.0

To expand on Will's answer, while .NET will not do this for you implicitly you can force it by adding an implicit operator to your TimeCheckRequest class:

public class TimeCheckRequest
{
    ...

    public static implicit operator TimeCheckRequest(object request)
    {
        return (TimeCheckRequest) request;
    }
}

I would not recommend this, however, since you can use a generic delegate instead without the performance cost of all the casting.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top