为什么 C# 不识别泛型

Why C# doesn't recognize the Generic

我想我迷路了。我尝试创建一个方法,其中包含两个通用条目并对其进行约束。

但是,编译器即使接收到指定泛型类型的实例,也表示无法进行转换。

这是什么解释?

编译错误信息(IResponseStreamMessage)中指向的“表达式类型”正是TResponse约束IResponseStreamMessage 。我没有看到什么?或者知道?

为了确保,这是 GetResponseStreamOf 方法签名:

public static IResponseStreamMessage GetResponseStreamOf(IRequestStreamMessage request)

更新:一旦我进行显式转换,它就会接受:

public static TResponse Get<TRequest, TResponse>(TRequest request, Func<System.IO.Stream> dataProviderFunction)
            where TRequest : IRequestStreamMessage
            where TResponse : IResponseStreamMessage
        {
            return (TResponse) StreamMessagesFactory.GetResponseStreamOf(request);
        }

但我还是不明白为什么我也有。

我认为对于您给定的代码,泛型不是一个好的选择,因为它没有提供任何好处。

TRequestTResponse 都没有真正从通用中获益,如果将它们替换为简单的 IRequestStreamMessageIResponseStreamMessage 它会按预期运行,并具有额外的好处实际编译。

至于为什么这是你应该考虑 Get<TRequest, TResponse> 方法的主体,唯一的内部方法 GetResponseStreamOf 不是通用的。

此代码与没有泛型的类似实现的唯一区别是转换(到 TResponse)的位置,在方法内或方法外,我怀疑这也可能是一个有争议的问题调用者很可能对界面也很好。

假设有两种可能的回应:

class ResponseA : IResponseStreamMessage
{
}
class ResponseB : IResponseStreamMessage
{
}

GetResponseStreamOf returns ResponseA(这是合法的,定义方式):

static public IResponseStreamMessage GetResponseStreamOf(IRequestStreamMessage request)
{
    return new ResponseA();
}

有人这样调用 Get(这也是合法的):

var response = MyClass.Get<IRequestStreamMessage, ResponseB>( ... );

来电者说它想要 ResponseB 回复。但是你的代码会 return ResponseA。虽然它们都实现了 IResponseStreamMessage,但 ResponseA 并未继承自 ResponseB,反之亦然。所以这会导致 运行-time cast 错误。编译器会抱怨,因为它无法知道这不会发生。

如果你绝对确定它不会发生,你必须告诉编译器。这就是需要显式转换的原因。

虽然 TResponseIResponseStreamMessage,但 IResponseStreamMessage 不是 TResponse,假设您有一个实现该接口的 class:

class CustomResponse : IResponseStreamMessage
{
}

然后您使用 class 作为通用 TResponse 的替代类型。方法 sig 看起来像这样:

public static CustomResponse Get<TRequest, CustomResponse>(TRequest request, Func<System.IO.Stream> dataProviderFunction);

问题是,什么类型 StreamMessagesFactory.GetResponseStreamOf 实际上 return,很可能不是 CustomResponse 所以,即使它 return 是 IResponseStreamMessage 你将无法将其 return 转换为 CustomResponse.

但是您可以检查 returned 响应是否属于 TResponse 类型,如果没有抛出异常,也不需要 TRequest,因为有什么区别如果你的 request 参数是 IRequestStreamMessageTRequest,sins TRequestIRequestStreamMessage,那么你的完整函数是:

public static TResponse Get<TResponse>(IRequestStreamMessage request, Func<System.IO.Stream> dataProviderFunction) where TResponse : IResponseStreamMessage
{
    var responseInterface = StreamMessagesFactory.GetResponseStreamOf(request);

    if (responseInterface is TResponse responseObject)
    {
        return responseObject;
    }
    else if (ReferenceEquals(responseInterface, null) && ReferenceEquals(default(TResponse), null))
    {
        return default(TResponse);
    }
    throw new InvalidOperationException($"Expected response of type {typeof(TResponse)}, but recieved a response of type {responseInterface?.GetType()}");          
}