c# - 通用类型约束检查

标签 c# generics

是否可以编写一些在编译或运行时(即通过任何方式)调用这些方法之一时失败的东西?

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 的约束不满足,所以这个构造是非法的。

对于封闭类型的类型参数,我们可以推理如下:

C 中,约束要求 U 是引用类型。

D中,T可以是类、接口(interface)、委托(delegate)或数组。在任何情况下,U 都必须与 T 相同,或者是 T 的基类,或者 T可转换为 via(可能是变体)隐式引用转换。不管怎样,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 有一个记录不完整的规则,它不允许类型参数的“已知为引用类型”-ness跨虚拟覆盖更改。我为此类方法重新编写了代码生成器,以尝试获得可以编译、通过验证程序并有效地 jit 几次 的东西,然后放弃并返回到 C# 2 所做的任何事情。

关于c# - 通用类型约束检查,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48471611/

相关文章:

ios - Equatable 实现似乎不适用于泛型

java - 分层模型中的泛型问题

c# - 是否可以删除数据表单元格的第一个元素,即字符串值?

c# - Lucene.NET 2.9 自定义过滤器添加授权

c# - iOS 上的 Ionic.Zip.Unity.dll ZlibException

c# - 无法从程序集办公室 writer.process() 加载类型 'System.Data.OleDb.OleDbType'

Java非泛型方法隐藏具有交集类型的泛型方法

Java - 带有列表的泛型

c# - 减少到服务器/数据库的往返

java - 通用对象的操作