【发布时间】:2012-02-24 05:05:31
【问题描述】:
我正在尝试编译以下代码:
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)?
谢谢。
更新:我使用泛型来强制执行返回类型,因此调用站点确切地知道会发生什么。在这里只返回 BaseResponse 会容易得多,但它会将确定具体返回类型的负担交给调用者而不是请求处理程序(它当然知道所有关于类型的事情)。
【问题讨论】:
-
首先,该方法不应该被称为 MakeResponse,因为它返回一个 TResponse?但更笼统地说:如果您必须检查事物的类型并且对某些特定类型采取一些特定操作,那么 您首先不是在编写通用代码,那么您为什么要使用 泛型?如果您有特殊的逻辑知道如何将 FooRequest 转换为 FooResponse 则创建一个方法,该方法接受 FooRequest 并返回 FooResponse;不需要泛型。
-
@Eric - 我正在研究一种责任链模式,其中路由节点只是向前传递消息,也许中间的某个节点会识别请求并返回正确的响应。不过,我应该在代码示例中说明清楚。
-
@forcey CoR 没有暗示任何关于泛型的内容,并且匹配实例类型不是泛型的目的。只需传递 BaseRequests 并使用
if (request is FooRequest) { ... } -
@ChrisShain 使用泛型,调用站点的类型会看起来更强大:
FooResponse response = chain.MakeRequest(new FooRequest)。换句话说,将BaseResponse->FooResponse转换为消息处理程序而不是调用站点。