为什么 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);
}
但我还是不明白为什么我也有。
我认为对于您给定的代码,泛型不是一个好的选择,因为它没有提供任何好处。
TRequest
或 TResponse
都没有真正从通用中获益,如果将它们替换为简单的 IRequestStreamMessage
和 IResponseStreamMessage
它会按预期运行,并具有额外的好处实际编译。
至于为什么这是你应该考虑 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 错误。编译器会抱怨,因为它无法知道这不会发生。
如果你绝对确定它不会发生,你必须告诉编译器。这就是需要显式转换的原因。
虽然 TResponse
是 IResponseStreamMessage
,但 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
参数是 IRequestStreamMessage
或 TRequest
,sins TRequest
是 IRequestStreamMessage
,那么你的完整函数是:
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()}");
}
我想我迷路了。我尝试创建一个方法,其中包含两个通用条目并对其进行约束。
但是,编译器即使接收到指定泛型类型的实例,也表示无法进行转换。
这是什么解释?
编译错误信息(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);
}
但我还是不明白为什么我也有。
我认为对于您给定的代码,泛型不是一个好的选择,因为它没有提供任何好处。
TRequest
或 TResponse
都没有真正从通用中获益,如果将它们替换为简单的 IRequestStreamMessage
和 IResponseStreamMessage
它会按预期运行,并具有额外的好处实际编译。
至于为什么这是你应该考虑 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 错误。编译器会抱怨,因为它无法知道这不会发生。
如果你绝对确定它不会发生,你必须告诉编译器。这就是需要显式转换的原因。
虽然 TResponse
是 IResponseStreamMessage
,但 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
参数是 IRequestStreamMessage
或 TRequest
,sins TRequest
是 IRequestStreamMessage
,那么你的完整函数是:
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()}");
}