我了解到匿名类型没有预定义的类型。类型是由编译器在编译时分配的,在代码级别无法知道分配的类型详细信息;这些详细信息只对CLR本身知道。我听说CLR中的这些匿名类型只被视为引用类型。那么我的问题是,是否在编译时会创建一个新的类型,类似于类或结构体,与在匿名类型中定义的只读属性相对应?
我知道匿名类型没有预定义的类型。
正确。除了 object 类型之外,匿名类型没有其他基础类型。
类型是由编译器在编译时分配给它的,分配的类型细节无法在代码级别上知道。
没错。
这些细节只有 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, 该类有一个类型为B.P的属性X,以便D1.M().GetType()
等于D2.M().GetType()
。请描述如何实现。
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() { … }
}
匿名类型是 C♯ 的一项特性,在 CLI 上没有等价物。它们只是编译成普通类型,编译器选择一个非常长且非常复杂的名称。请注意,规范保证具有相同结构的两个匿名类型(在同一程序集内)实际上是相同的类型,因此编译器还需要考虑这一点,并仅生成一个类型(并为两个使用处生成相同的名称)。
这些匿名类是直接从对象派生的。通常在选择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);
B.P
比AT.X
更不可访问。而且,您不能将其嵌套在D1
或D2
下面,因为受保护的属性X
在其他类中不可用...请给我指点一下,@EricLippert。 - Xiaoy312