【问题标题】:Anonymous Types C#匿名类型 C#
【发布时间】:2016-12-20 19:58:03
【问题描述】:

我了解匿名类型没有自己的预定义类型。类型是由编译器在编译类型时分配给它的,在编译时分配的类型的详细信息在代码级别是未知的;这些细节是 CLR 自己知道的。我听说 CLR 中的这些匿名类型被视为仅作为引用类型。所以我的问题是,是否在编译时创建一个新的类型,如类或结构,对应于匿名类型中定义的只读属性?

【问题讨论】:

    标签: c# anonymous-types


    【解决方案1】:

    我了解匿名类型没有自己的预定义类型。

    正确。除了匿名类型共有的对象之外,没有其他基本类型。

    类型是由编译器在编译类型时分配给它的,在编译时分配的类型的详细信息在代码级别是不知道的

    没错。

    这些细节是 CLR 自己知道的。

    我不知道你在说什么“细节”或“CLR 知道”是什么意思。

    我听说 CLR 中的这些匿名类型被视为仅作为引用类型。

    你没听错。

    所以我的问题是,是否在编译时创建一个新类型,如类或结构,对应于匿名类型中定义的只读属性?

    是的。创建了一个新类。

    注意在一个程序集中如果有两个匿名类型具有相同的属性名称,相同的属性类型,以相同的顺序,那么只创建一个类型。这是由语言规范保证的。

    运动:

    // Code in Assembly B:
    public class B { protected class P {} }
    
    // Code in Assembly D (references assembly B)
    class D1 : B { 
      public static object M() { return new { X = new B.P() }; }
    }
    class D2 : B { 
      public static object M() { return new { X = new B.P() }; }
    }
    

    您需要在程序集 D 中生成一个 single 类声明,该声明具有 B.P 类型的属性 X,使得 D1.M().GetType() 等于 D2.M().GetType()。描述如何做到这一点。

    【讨论】:

    • “在同一个程序中,两个匿名对象初始值设定项以相同的顺序指定一系列相同名称和编译时类型的属性,将生成相同匿名类型的实例。” -(C# 4.0 规范,7.6.10.6)
    • @Xiaoy312:没错。现在,如果必须在程序集 D 中为上述匿名类型生成这样的类型,如果必须编写源代码,该类型会是什么样子?
    • 直到现在才注意到protected 关键字。我想它会是这样的:public abstract class CompilerMagic : B { public class AnonymousType { B.P x; public B.P X { get { return x; } } } }?
    • 实际上,这仍然行不通,因为B.PAT.X 更难访问。而且,您不能将它嵌套在D1D2 下,因为受保护的属性X 在其他类中不可用......请启发我,@EricLippert。
    • @Xiaoy312:你的反对​​都是对的,但还是可以做到的。提示:在 C# 1.0 中无法做到这一点。
    【解决方案2】:

    匿名类型是直接从对象派生的类类型,不能转换为除对象之外的任何类型。编译器为每个匿名类型提供一个名称,尽管您的应用程序无法访问它。从公共语言运行时的角度来看,匿名类型与任何其他引用类型没有区别

    来源:https://msdn.microsoft.com/en-us/library/bb397696.aspx

    【讨论】:

      【解决方案3】:

      除了没有程序员可访问的名称外,匿名类型非常简单:编译器根据您所做的分配生成它们,并负责将相同方法中的相同匿名类型正确地合并为单个运行时类型。

      根据 C# 语言规范第 7.6.10.6 节,匿名类型始终是类,而不是 structs。表单的匿名对象初始化器

      new { p1 = e1 , p2 = e2 , ... pn = en }
      

      声明表单的匿名类型

      class __Anonymous1 {
          private readonly T1 f1 ;
          private readonly T2 f2 ;
          ...
          private readonly Tn fn ;
          public __Anonymous1(T1 a1, T2 a2,…, Tn an) {
              f1 = a1 ;
              f2 = a2 ;
              ...
              fn = an ;
          }
          public T1 p1 { get { return f1 ; } }
          public T2 p2 { get { return f2 ; } }
          ...
          public Tn pn { get { return fn ; } }
          public override bool Equals(object __o) { … }
          public override int GetHashCode() { … }
      }
      

      【讨论】:

      • 虽然逻辑上是生成的代码,但这实际上是一个相当大的简化。请参阅我的答案以了解原因。
      【解决方案4】:

      这些匿名类直接派生自对象。通常,它们用于选择 LINQ 查询以将只读属性封装到单个对象中。

      LINQ 示例(FirstName 和 LastName 作为 FullName):

      public class Person {
          public int Id {get;set;}
          public string FirstName {get;set;}
          public string LastName {get;set;}
      }
      
      IEnumerable<int> personIds = persons
          .Select(p => new { Id = p.Id, FullName = p.FirstName + " " + p.LastName})
          .Where(a => a.FullName == "John Smith")
          .Select(a => a.Id);
      

      【讨论】:

        【解决方案5】:

        匿名类型是 C♯ 功能,在 CLI 上没有等效功能。它们被简单地编译为普通类型,编译器选择了一个非常长且非常复杂的名称。请注意,规范保证具有相同结构的两个匿名类型(在同一个程序集中)实际上是相同的类型,因此编译器也需要考虑到这一点,并且只生成一种类型(并为两者生成相同的名称使用网站)。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2010-09-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-05-01
          • 2010-12-25
          • 1970-01-01
          相关资源
          最近更新 更多