将混凝土浇筑到通用型?

我正在尝试编译以下代码:

public class BaseRequest where TResponse : BaseResponse {} public class BaseResponse {} public class FooRequest : BaseRequest {} public class FooResponse : BaseResponse {} ... public TResponse MakeRequest(BaseRequest request) where TResponse : BaseResponse { } 

我希望我可以调用MakeRequest(new FooRequest())并将返回值作为FooResponse 。 被调用者不必知道FooRequest并且可以将其传递给另一个处理程序。 签名工作正常,但我无法实现MakeRequest方法。 如果我实现它像:

 public TResponse MakeRequest(BaseRequest 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指定。 有没有办法解决这个问题,而不涉及讨厌的reflection(在这种情况下,我宁愿返回BaseResponse )?

谢谢。

更新 :我正在使用generics来强制执行返回类型,因此调用站点确切地知道会发生什么。 在这里返回BaseResponse要容易BaseResponse ,但是它将具体的返回类型的负担放到了调用者而不是请求处理程序(当然知道关于输入的所有内容)。

正如我在评论中所说,我怀疑你做错了。 这看起来像滥用generics。

也就是说,你告诉编译器“我知道比你更多的类型信息”的方式是通过强制转换。

 var response = new FooResponse(...); return (TResponse)(object)response; 

转换为对象然后转向TResponse告诉编译器“我知道从响应到TResponse有一个标识,拆箱或引用转换”。 如果你错了,你会在运行时得到一个例外。

在我看来,您应该从非generics版本BaseRequest派生您的BaseRequest类,然后将您的函数编写为:

 public BaseResponse MakeRequest(BaseRequest request) 

这似乎是正确的方法,因为你甚至没有提到函数内部的类型。

在我看来,仿制药只是作为语法糖。 以你的方式编写函数所能获得的是能够编写:

 FooResponse r = MakeRequest(new FooRequest(...)) 

而不是这个:

 FooResponse r = (FooResponse)MakeRequest(new FooRequest(...)) 

所以好处并不大。 事实上,你被自己的代码搞糊涂了,以至于你无法看到丢失的东西是强制转换意味着代码可能比非generics方式更不清楚。

哦,你的方法的另一个缺点是你将失去做的能力:

 var requests = new List { new FooRequest(), new BarRequest() }; var responses = new List (); foreach(var request in requests) { responses.Add(MakeRequest(request)); } 

或者你可以做的是:

 public BaseResponse MakeRequest(BaseRequest request) { /* thing that does the work */ } public TResponse MakeRequest(BaseRequest request) { // Just for the nice syntax return (TResponse)MakeRequest(request); } 

但这看起来真的很复杂。 无论如何,我会让你反思