views:

849

answers:

6

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?

+7  A: 

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 :)

emaster70
Unfortunately, I'm stuck with .NET 2.0, so your solution won't work for me.
AlexWalker
.NET 2.0 supports generics
Adam Lassek
That's true, however Func was added with LINQ in .NET 3.5, though.
Andy
True, this should be written using a generic delegate instead of Func
Adam Lassek
You can define your own Func delegate easily enough in .net 2.
Reed Copsey
+1  A: 

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;
Will
Yes, you're definitely right on that. My object will never be converted to TimeCheckRequest automatically. Darn type-safe language.
AlexWalker
You can define an implicit operator in the TimeCheckRequest class to do this without manually casting to object.
Adam Lassek
Creating an implicit operator for a type's base class (esp. for Object) doesn't seem like the best idea in the world.... I'm not sure if there are any official pronouncements on the subject, but it has an odor about it...
Will
+5  A: 

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.
}
Jon Skeet
A: 

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.

Adam Lassek
Code doesn't compile: error CS0553: 'MyType.implicit operator MyType(object)': user-defined conversions to or from a base class are not allowed
Wesley Wiser
A: 

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 :)

emaster70
+2  A: 

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);
}
AlexWalker