【问题标题】:C# - Type objects of constructed classesC# - 构造类的类型对象
【发布时间】:2017-04-14 07:32:04
【问题描述】:

我读过引用类型都使用相同的构造类:

泛型对引用类型的工作方式有所不同。第一次使用任何引用类型构造泛型类型时,运行时会创建一个专门的泛型类型,其中对象引用替换 MSIL 中的参数。然后,每次使用引用类型作为参数实例化构造类型时,无论它是什么类型,运行时都会重用先前创建的泛型类型的专用版本。这是可能的,因为所有引用的大小都相同。 (Generics in the Run Time (C# Programming Guide))

但是,当对基于具有不同类型参数的相同泛型的构造对象调用 GetType() 时,会收到两种不同的类型。其中 A 和 B 都是类,而 RefType 是泛型:

RefType<A> a = new RefType<A>();
RefType<B> b = new RefType<B>();
Console.WriteLine("a type is "+a.GetType());
Console.WriteLine("b type is "+b.GetType());

结果:

"a type is RefType`1[A]"
"b type is RefType`1[B]"

这是否意味着即使没有“真正的”专门实例化,CLR 也会为不同的构造类型处理 Type 对象的创建? 有没有办法直接查看 CLR 生成和不生成的内容?

【问题讨论】:

  • 类型仍然非常不同。文本试图说的(它可以以更清晰的方式做,并且那里有很多其他不好的写作)是用于实现这些类型的实际代码可以为所有具有引用类型的实例共享。不过,这是一个程序员通常不太关心的实现细节。您需要连接一个调试器并检查 jitted 代码才能看到这一点;我不确定 C# 级别是否有任何方法可以验证这一点。

标签: c# generics types


【解决方案1】:

这是否意味着即使没有“真正的”专门实例化,CLR 也会为不同的构造类型处理 Type 对象的创建?

是的。考虑到运行时类型检查是语言的重要组成部分。

var x = new List<string>() as List<object>;

这应该将x 初始化为null。如果new List&lt;string&gt;() 的运行时类型信息不知何故丢失了泛型类型参数,这将无法正常工作。

有没有办法直接查看 CLR 生成和不生成的内容?

class G<T> { public void f() { } }
class A { }
class B { }
struct C { }
struct D { }
enum E : int { }

static void Main(string[] args)
{
    Console.WriteLine(typeof(G<object>).GetMethod("f").MethodHandle.Value);
    Console.WriteLine(typeof(G<string>).GetMethod("f").MethodHandle.Value);
    Console.WriteLine(typeof(G<A>).GetMethod("f").MethodHandle.Value);
    Console.WriteLine(typeof(G<B>).GetMethod("f").MethodHandle.Value);
    Console.WriteLine(typeof(G<C>).GetMethod("f").MethodHandle.Value);
    Console.WriteLine(typeof(G<D>).GetMethod("f").MethodHandle.Value);
    Console.WriteLine(typeof(G<E>).GetMethod("f").MethodHandle.Value);
    Console.WriteLine(typeof(G<int>).GetMethod("f").MethodHandle.Value);
}

你会看到G&lt;object&gt;.fG&lt;string&gt;.fG&lt;A&gt;.fG&lt;B&gt;.f具有相同的方法句柄,但G&lt;C&gt;.fG&lt;D&gt;.fG&lt;E&gt;.fG&lt;int&gt;.f都有不同的方法句柄。甚至 G&lt;E&gt;.fG&lt;int&gt;.f 也不共享实现。

【讨论】:

  • 为了完整起见(或作为对读者的练习),您可以验证G&lt;string&gt; 与其他引用类型共享其实现,而G&lt;int&gt; 既不与引用类型共享实现,也不与@ 987654338@.
  • @JeroenMostert 感谢您的建议,补充,以及其他一些情况。
【解决方案2】:

Type 对象以高抽象级别提供类型信息并告诉您逻辑上的类型是什么,而泛型的实现是一个低级别的细节,您不应该依赖它。实施细节随时可能发生变化。

T&lt;A&gt;T&lt;B&gt; 是两种不同的类型,因此它们必须由不同的Type 对象来描述。这是因为Type 对象不仅为T&lt;&gt; 生成信息,还为AB 生成信息,即针对泛型类型参数。这两种类型共享相同的代码库这一事实没有区别。

Type 对象属于 API。您可以在代码中使用此信息。 Type 类将来可能会扩展以反映该语言的新特性,但这不是重大变化。

当您想编写高效的代码时,最好了解实现细节。一些低级工具(O/R-mappers、代码编织器等);但是,有时确实取决于实现细节。

【讨论】:

  • 有用的建议,但不是问题的答案。有时您想深入了解实现细节。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-17
  • 2022-08-19
相关资源
最近更新 更多