将混凝土类型浇筑成通用类型?

Tod*_* Li 4 c# generics

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

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
{
}
Run Code Online (Sandbox Code Playgroud)

我希望我可以调用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);
    }
}
Run Code Online (Sandbox Code Playgroud)

但该***行不会编译,因为编译器不知道FooResponse是一个TResponse.我知道这是因为它已经指定了FooRequest.有没有办法解决这个问题,而不涉及讨厌的反思(在这种情况下,我宁愿返回BaseResponse)?

谢谢.

更新:我正在使用泛型来强制执行返回类型,以便调用站点确切地知道预期的内容.回到BaseResponse这里要容易得多,但是它把具体的返回类型的负担放到了调用者而不是请求处理程序(当然知道关于打字的所有内容).

Eri*_*ert 9

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

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

var response = new FooResponse(...);   
return (TResponse)(object)response;
Run Code Online (Sandbox Code Playgroud)

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