[英]Generic type constraint checking
是否有可能在调用这些方法之一时编写在编译或运行时(即以任何方式)失败的东西?
public static void Register<TInterface, TImplementation>()
where TImplementation : class, TInterface
{
}
public static void RegisterRestrictive<TInterface, TImplementation>()
where TInterface : class
where TImplementation : class, TInterface
{
}
以下将通过两个例子:
public interface IInterface
{
}
public class Implementation : IInterface
{
}
public void Test()
{
Register<IInterface, Implementation>();
RegisterRestrictive<IInterface, Implementation>();
}
我不认为是,因为你不能扩展结构?
问题是,据我了解:
class C<T, U> where T : class, U where U : class { }
class D<T, U> where T : class, U { }
是否存在对D
而言合法的结构对C
不合法 ?
如果U
和T
是封闭类型 ,则不是。 也就是说,其中没有类型参数的类型。 正如Jon Hanna的回答指出的那样, 开放式可能会导致问题:
class N<T, U> where T : class, U { C<T, U> c; D<T, U> d; }
D
的限制没有得到满足,因此这种结构是非法的。
对于封闭类型的类型参数,我们可以推断如下:
在C
,约束要求U
是引用类型。
在D
, T
可以是类,接口,委托或数组。 在任何情况下, U
必须是相同T
,或基类的T
,或东西T
可转化为经由(可能变体)隐式引用转换。 无论如何, U
是参考类型。
请注意,无论是C#编译器,CLR验证器还是JIT编译器都不需要推断出U
始终是一个引用类型! 例如,在这种情况下,C#编译器会对U
用法生成不必要的装箱指令,即使您和我知道U
不会是正在构造的值类型。
这可能导致U
被装箱然后立即取消装箱的情况,以及我最后一次检查 - 这是,呃,十年前 - 抖动没有为该场景生成最佳代码。 毫无疑问,自从我上次检查以来,抖动已被重写了一次或多次,你可能不应该接受我的话。
这里的好习惯是将约束放在那里并拼出来。
一些有趣的相关事实:
你可以通过拉扯类似的恶作剧来进入类似的情况
class B<T> { public virtual void M<U>(U u) where U : T {} }
class D : B<int> { public override void M<U>(U u) { } }
请注意,C#不允许您重新声明约束,现在where U : int
。 但你不能用除int之外的任何东西做M
的泛型构造。
这可能导致IL生成中的一些真正奇怪的场景,因为CLR具有记录不良的规则,因此它不允许类型参数的“已知为参考类型”的性能在虚拟覆盖。 我为这些方法重新编写了codegen,试图在放弃并返回C#2所做的任何事情之前尝试获得可以编译,传递验证器和jit高效几次的内容。
是否有可能在调用这些方法之一时编写在编译或运行时(即以任何方式)失败的东西?
是的,这在编译时失败了:
public static void CallThem<TA, TB>()
where TB : class, TA
{
Register<TA, TB>(); // Fine
RegisterRestrictive<TA, TB>(); // CS0452
}
没有一对与TInterface
和TImplementation
仅匹配其中一个的具体类型,但调用方法的类型参数类型当然可以,而类型参数类型是我们在设计API时需要考虑的类型以及具体类型。
约束不涉及其他约束的推断。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.