Может ли делегат C# использовать тип объекта для более общего использования?
-
09-09-2019 - |
Вопрос
Я хотел бы создать делегат и метод, который можно использовать для вызова любого количества веб-сервисов, необходимых моему приложению:
Пример:
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;
}
}
Я бы нет Однако рекомендуется это сделать, поскольку вы можете использовать универсальный делегат вместо этого без затрат на производительность всего кастинга.