Может ли делегат C # использовать тип объекта, чтобы быть более общим? - PullRequest
2 голосов
/ 09 апреля 2009

Я хотел бы создать делегата и метод, который можно использовать для вызова любого числа веб-служб, которые требуются моему приложению:

Пример:

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

Но, к сожалению, когда я пытаюсь скомпилировать, я получаю следующие ошибки:

Без перегрузки для 'GetTheDate' соответствует делегату 'WebMethodToCall' Никакая перегрузка для 'GetTheTime' не соответствует делегату 'WebMethodToCall'

Кажется, что делегат должен работать.

WebServices.GetTheDate и WebServices.GetTheTime оба принимают один параметр (DateCheckRequest и TimeCheckRequest, соответственно) и оба возвращают значение.

Значит, делегат не совпадает с сигнатурой двух веб-методов? (оба принимают и возвращают типы, полученные из объекта).

Можно ли использовать тип объекта для создания очень многократно используемого делегата в .NET 2.0?

Ответы [ 6 ]

7 голосов
/ 09 апреля 2009

Я бы посоветовал вам изменить код на что-то вроде:


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

Таким образом, вы можете избежать всех отвратительных ударов :))

5 голосов
/ 09 апреля 2009

Я предлагаю вам использовать универсальный делегат, такой как 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);
}

В таком случае вы также сделаете CallWebMethod родовым:

public TResponse CallWebMethod<TRequest, TResponse>
    (Func<TRequest, TResponse> method, TRequest request)
{
    // Whatever you do in here.
}
2 голосов
/ 09 апреля 2009

Я решил благодаря комментариям здесь.

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);
}
1 голос
/ 09 апреля 2009

Да, но вам придется переписать WebServices.GetTheData и GetTheTime, чтобы принимать объекты или предоставлять перегрузки, которые принимают объекты.

Это потому, что вы не можете upcast объектов в .NET неявно. Другими словами, вы можете сделать это:

TimeCheckRequest myTimeCheckRequest;
object foo = myTimeCheckRequest;

но вы не можете сделать это:

object myTimeCheckRequest;
TimeCheckRequest  foo = myTimeCheckRequest;
0 голосов
/ 09 апреля 2009

Вы можете определить Func как:

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

Это определение не требует ничего, что недоступно в .NET 2.0 и добавлено к фрагменту кода, который я разместил выше, решает вашу проблему:)

0 голосов
/ 09 апреля 2009

ОБНОВЛЕНИЕ: Может быть больше не действительным? Не знаю, я сделал это в C # 2.0

Чтобы расширить ответ Уилла, в то время как .NET не сделает этого для вас неявным образом, вы можете принудительно добавить его в свой класс TimeCheckRequest:

public class TimeCheckRequest
{
    ...

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

Я бы не рекомендовал бы это, тем не менее, поскольку вместо него можно использовать универсальный делегат без затрат производительности для всех приведений.

...