Может ли делегат C# использовать тип объекта для более общего использования?

StackOverflow https://stackoverflow.com/questions/734698

Вопрос

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

Пример:

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?

Это было полезно?

Решение

Я предлагаю вам использовать общий делегат, например 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.
}

Другие советы

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


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

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

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

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

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

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

TimeCheckRequest myTimeCheckRequest;
object foo = myTimeCheckRequest;

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

object myTimeCheckRequest;
TimeCheckRequest  foo = myTimeCheckRequest;

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

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

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

ОБНОВЛЯТЬ: Может уже недействителен?Не знаю, я сделал это на C# 2.0.

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

public class TimeCheckRequest
{
    ...

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top