Я пытаюсь скомпилировать следующий код:Литой бетонный тип общего типа?
public class BaseRequest<TResponse> where TResponse : BaseResponse {}
public class BaseResponse {}
public class FooRequest : BaseRequest<FooResponse> {}
public class FooResponse : BaseResponse {}
...
public TResponse MakeRequest<TResponse>(BaseRequest<TResponse> request)
where TResponse : BaseResponse
{
}
Я желаю я могу назвать MakeRequest(new FooRequest())
и получить возвращаемое значение в качестве FooResponse
. Вызов не должен знать о FooRequest
и может передать его другому обработчику. Подписи работали нормально, однако я не могу реализовать метод MakeRequest
. Если я реализую это нравится:
public TResponse MakeRequest<TResponse>(BaseRequest<TResponse> request)
where TResponse : BaseResponse
{
FooRequest fooRequest = request as FooRequest;
if (fooRequest != null) // if I can handle the request, handle it
{
return new FooResponse(...); // ***
}
BarRequest barRequest = request as BarRequest;
if (barRequest != null)
{
return new BarResponse(...);
}
else // otherwise, pass it on to the next node
{
// maybe it will handle a BazRequest, who knows
return nextNode.MakeRequest(request);
}
}
Но ***
линия не будет компилироваться, потому что компилятор не знает FooResponse
является TResponse
. Я знаю, потому что он указан в FooRequest
. Есть ли способ обойти это без участия неприятного отражения (в таком случае я предпочел бы вместо этого вернуть BaseResponse
)?
Спасибо.
Обновление: Я использую generics для принудительного ввода типа возврата, чтобы сайт вызова точно знал, чего ожидать. Было бы намного проще вернуть BaseResponse
здесь, но это ставит бремя выяснить конкретный тип возврата вызывающему, а не обработчик запроса (который, конечно же, знает все о наборе текста).
Во-первых, не следует ли вызывать метод MakeResponse, так как он возвращает TResponse? Но в более общем плане: если вам нужно проверить тип вещи и принять какое-то конкретное действие по определенному типу, то ** вы не пишете общий код в первую очередь **, так почему вы используете * generics *? Если у вас есть специальная логика, которая знает, как превратить FooRequest в FooResponse, тогда создайте метод, который принимает FooRequest и возвращает FooResponse; не требуется никаких дженериков. –
@ Эрик. Я работаю над шаблоном Chain of Responsibility, в котором узлы маршрутизации просто передают сообщение вперед, и, возможно, какой-то узел посередине распознает запрос и возвращает правильный ответ. Однако я должен прояснить это в примере кода. –
@forcey CoR не подразумевает ничего общего с дженериками, а совпадение по типу экземпляра не является целью дженериков. Просто пройдите по BaseRequests и используйте 'if (request is FooRequest) {...}' –