通用类型约束检查

马多克斯

是否有可能在调用这些方法之一时编写会在编译或运行时(即以任何方式)失败的内容?

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>();
}

我不这么认为,因为您无法扩展结构?

正因为如此而问https://github.com/aspnet/DependencyInjection/pull/624

埃里克·利珀特

据我了解,问题是:

class C<T, U> where T : class, U where U : class { }
class D<T, U> where T : class, U { }

有没有一种结构,即是合法的,D这是不合法的C

不是UT封闭类型也就是说,其中没有类型参数的类型。正如乔恩·汉纳(Jon Hanna)的答案所指出的那样,开放类型可能会在这里引起问题:

class N<T, U> where T : class, U { C<T, U> c; D<T, U> d; }

D的约束未得到满足,因此此构造是非法的。

对于封闭类型的类型参数,我们可以得出以下结论:

在中CU由约束要求是引用类型。

在中DT可以是类,接口,委托或数组。在每种情况下,U都必须与T,或的基类相同T,或者某些东西T可以通过隐式引用转换(可能是变体)转换为。无论如何,U都是引用类型。

请注意,尽管不需要C#编译器,CLR验证程序或JIT编译器来推断U总是引用类型!例如,在这种情况下,C#编译器可以并且会针对的用法生成不必要的装箱指令U,即使您和我知道这U不会成为正在构造的值类型。

这可能导致将aU装箱然后立即拆箱的情况,以及我上次检查时(即十年前),这种抖动未针对该情况生成最佳代码。自从我上次检查以来,毫无疑问,抖动已经被重写了一次或多次,因此您可能不应该相信这一点。

这里的一个好习惯是将约束放到那里并将其拼写出来。


一些有趣的事实:

您可以通过拉扯类似的恶作剧来陷入类似的情况

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但是M除了int之外,您不能使用泛型构造任何东西。

这可能导致IL生成过程中出现一些真正奇怪的情况,因为CLR的文档记载不充分,因此它不允许类型参数的“已知为引用类型”性质在整个过程中发生变化。虚拟替代。我重做了代码生成这样的方法来尝试得到的东西,将汇编,通过验证和JIT有效几个放弃并回到任何C#2之前做过倍。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章