【问题标题】:Why is type constraint not always enforced when it is set to class? [duplicate]为什么类型约束在设置为类时并不总是强制执行? [复制]
【发布时间】:2018-09-10 19:07:44
【问题描述】:

我有这个代码:

void Foo<T>(T x) {} where T:class

interface IBar {}

IBar GetBar() {...}

尽管隐式类型约束设置为类,我仍然能够抽象调用并传递接口:

Foo<IBar>(GetBar());

为什么在这种情况下不强制类型约束?

但是,如果我使用这种结构:

void Doo<T>(T x) {
    Foo<T>(x);
}

然后编译器会抛出一个错误并抱怨类型'T'必须是一个引用类型,这是预期的。

【问题讨论】:

  • 在第二个构造中,你没有where 条件。
  • 我认为这与装箱有关,我曾认为使用实现接口的结构会显示错误,但令人惊讶的是它没有。 This was unexpected,我猜 T 被装箱为 object(或其接口类型),然后满足 where T : class 约束。
  • @RonBeyer IL_0009: ldloc.0 // myStruct IL_000A: box UserQuery.MyStruct IL_000F: call UserQuery+Program.Foo&lt;IFace&gt; 似乎是对结构如何/为什么工作的正确评估。
  • @JonathonChase 谢谢,我没有去检查 IL,但它似乎很有可能。
  • 因为你不能自己实例化一个接口。它必须是实现接口的类。所以这是有道理的。

标签: c# generics type-constraints


【解决方案1】:

接口是引用类型。 where : class 约束并不意味着 T 必须是一个类,它说 T 必须是一个引用类型。

【讨论】:

    【解决方案2】:

    实际上,类型约束强制执行的。您似乎认为接口不是类。但是接口只是类的一种类型:从技术上讲,它是一个抽象类,进一步的限制是不能有具体的成员。

    The docwhere T : class 声明了这一点:

    类型参数必须是引用类型。此约束也适用于任何类、接口、委托或数组类型。

    【讨论】:

    • 接口不是类。接口是与 C# 和 CIL 术语中的类不同的类型。此处使用class 关键字这一事实并没有改变这一点。
    • class 约束限制为 reference type 而不是 class。接口绝对不是抽象类。
    • 来自微软自己对抽象类的定义:“抽象类不能被实例化。抽象类的目的是提供一个基类的通用定义,多个派生类可以共享。例如,类库可以定义一个抽象类,用作其许多函数的参数,并要求使用该库的程序员通过创建派生类来提供他们自己的类实现。”这对于接口同样适用,尽管实现语义不同。这就是为什么该约束适用于所有 IMO。
    • 微软的另一个例子:“abstract 修饰符表示被修改的东西有一个缺失或不完整的实现。”接口也是如此。所以,你的断言相反,我没有找到 C# 或 CIL 术语中的证据表明除了句法语义之外的任何意义上的区别,除了接口是抽象类的子集。
    • 现在,为了支持我的断言,接口在技术上是抽象类的子集,这是 UML 元类语义所采用的方法:所有类(意味着具体类、抽象类和接口)都是抽象的Classifier 元类,它有一个isAbstract 属性。抽象类和接口都将该属性设置为 true,而接口有进一步的约束,即所有成员都必须是公共的和抽象的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-26
    • 2016-11-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多