为什么我不能从具有泛型参数的类型转换为泛型接口,该泛型参数是我接口中泛型参数的子类型?
Why can I not cast to a generic interface from a type with a generic argument which is a subtype of the generic argument in my interface?
给定以下界面:
public interface IController<T> where T: Request {
Response HandleRequest(T request);
}
以及以下请求 class:
public BlergRequest : Request {
}
以及以下控制器实现:
public BlergController : IController<BlergRequest> {
public Response HandleRequest(BlergRequest request) {
return new Response("Here's your blergs!");
}
}
为什么下面是 InvalidCastException
?
IController<Request> controller = (IController<Request>)new BlergController();
在我的 "Immediate" window 调试器中,我有以下内容:
typeof(Request).IsAssignableFrom(typeof(BlergRequest))
true
typeof(IController<Request>).IsAssignableFrom(typeof(BlergController))
false
什么给?我认为这就是通用约束的全部意义?
跟进@Asad 的评论;试试这个:
public class Request { }
public class Response {
public Response(string text) {}
}
public interface IController<out T> where T: Request {
Response HandleRequest(T request);
}
public class BlergRequest : Request { }
public class BlergController : IController<BlergRequest> {
public Response HandleRequest(BlergRequest request) {
return new Response("Here's your blergs!");
}
public void Test() {
IController<Request> controller = new BlergController();
}
}
然而,IController.HandleRequest 的参数(可能)不是所写的协变。然而,扩展接口的使用,使这个编译干净利落,没有变化的规范,这可能满足您的需求:
public interface IRequest { }
public class Request : IRequest { }
public class Response {
public Response(string text) {}
}
public interface IController<T> where T: IRequest {
Response HandleRequest(T request);
}
public class BlergRequest : IRequest { }
public class BlergController : IController<IRequest> {
public Response HandleRequest(BlergRequest request) {
return new Response("Here's your blergs!");
}
public void Test() {
IController<IRequest> controller = new BlergController();
}
}
从类型安全的角度来看,不允许您这样做是完全合乎逻辑的。如果 IController<BlergRequest>
在各种方法中接受 BlergRequests
(在您的示例中,HandleRequest
就是这样一种方法),按理说这些方法可能会调用仅 的成员 在 BlergRequest
上可用,但在 Request
上不可用。因此,您不能将 IController<BlergRequest>
分配(或强制转换)为 IController<Request>
.
另一方面,如果您的界面只有 returning BlergRequest
,并且从未使用过它们,那么它可以 return a BlergRequest
到任何需要 Request
的消费代码。在这种情况下,您的接口将是 covariant in T
,您可以使用协变 out
修饰符标记类型参数 T
。然后,您可以在需要 IController<Request>
的地方分配 IController<BlergRequest>
。
给定以下界面:
public interface IController<T> where T: Request {
Response HandleRequest(T request);
}
以及以下请求 class:
public BlergRequest : Request {
}
以及以下控制器实现:
public BlergController : IController<BlergRequest> {
public Response HandleRequest(BlergRequest request) {
return new Response("Here's your blergs!");
}
}
为什么下面是 InvalidCastException
?
IController<Request> controller = (IController<Request>)new BlergController();
在我的 "Immediate" window 调试器中,我有以下内容:
typeof(Request).IsAssignableFrom(typeof(BlergRequest))
true
typeof(IController<Request>).IsAssignableFrom(typeof(BlergController))
false
什么给?我认为这就是通用约束的全部意义?
跟进@Asad 的评论;试试这个:
public class Request { }
public class Response {
public Response(string text) {}
}
public interface IController<out T> where T: Request {
Response HandleRequest(T request);
}
public class BlergRequest : Request { }
public class BlergController : IController<BlergRequest> {
public Response HandleRequest(BlergRequest request) {
return new Response("Here's your blergs!");
}
public void Test() {
IController<Request> controller = new BlergController();
}
}
然而,IController.HandleRequest 的参数(可能)不是所写的协变。然而,扩展接口的使用,使这个编译干净利落,没有变化的规范,这可能满足您的需求:
public interface IRequest { }
public class Request : IRequest { }
public class Response {
public Response(string text) {}
}
public interface IController<T> where T: IRequest {
Response HandleRequest(T request);
}
public class BlergRequest : IRequest { }
public class BlergController : IController<IRequest> {
public Response HandleRequest(BlergRequest request) {
return new Response("Here's your blergs!");
}
public void Test() {
IController<IRequest> controller = new BlergController();
}
}
从类型安全的角度来看,不允许您这样做是完全合乎逻辑的。如果 IController<BlergRequest>
在各种方法中接受 BlergRequests
(在您的示例中,HandleRequest
就是这样一种方法),按理说这些方法可能会调用仅 的成员 在 BlergRequest
上可用,但在 Request
上不可用。因此,您不能将 IController<BlergRequest>
分配(或强制转换)为 IController<Request>
.
另一方面,如果您的界面只有 returning BlergRequest
,并且从未使用过它们,那么它可以 return a BlergRequest
到任何需要 Request
的消费代码。在这种情况下,您的接口将是 covariant in T
,您可以使用协变 out
修饰符标记类型参数 T
。然后,您可以在需要 IController<Request>
的地方分配 IController<BlergRequest>
。