博客园  :: 首页  :: 联系 :: 管理

C# 2008 学习笔记 - 匿名类型

Posted on 2008-02-20 11:31  sunrack  阅读(321)  评论(0编辑  收藏  举报
一、定义

使用关键字var和对象初始化器来生成一个匿名类型。

// Make an anonymous type representing a car.
var myCar = new { Color = "Bright Pink", Make = "Saab", CurrentSpeed = 55 };
// Now show the color and make.
Console.WriteLine("My car is a {0} {1}.", myCar.Color, myCar.Make);


二、匿名类型的内部表示

static void ReflectOverAnonymousType(object obj)
{
Console.WriteLine(
"obj is an instance of: {0}", obj.GetType().Name);
Console.WriteLine(
"Base class of {0} is {1}",
obj.GetType().Name,
obj.GetType().BaseType);
Console.WriteLine(
"obj.ToString() = {0}", obj.ToString());
Console.WriteLine(
"obj.GetHashCode() = {0}", obj.GetHashCode());
Console.WriteLine();
}

static void Main(string[] args)
{
Console.WriteLine(
"***** Fun with Anonymous types *****\n");
// Make an anonymous type representing a car.
var myCar = new {Color = "Bright Pink", Make = "Saab", CurrentSpeed = 55};

// Reflect over what the compiler generated.
ReflectOverAnonymousType(myCar);
Console.ReadLine();
}

其实为对象生成了若干只读属性

internal sealed class <>f__AnonymousType0<<Color>j__TPar,
<Make>j__TPar, <CurrentSpeed>j__TPar>
{
// Read-only fields
private readonly <Color>j__TPar <Color>i__Field;
private readonly <CurrentSpeed>j__TPar <CurrentSpeed>i__Field;
private readonly <Make>j__TPar <Make>i__Field;
// Default constructor
public <>f__AnonymousType0(<Color>j__TPar Color,
<Make>j__TPar Make, <CurrentSpeed>j__TPar CurrentSpeed);
// Overridden methods
public override bool Equals(object value);
public override int GetHashCode();
public override string ToString();
// Read-only properties
public <Color>j__TPar Color { get; }
public <CurrentSpeed>j__TPar CurrentSpeed { get; }
public <Make>j__TPar Make { get; }
}

三、ToString() 和 GetHashCode()的实现
所有的匿名类型自动继承自System.Object ,并且重写了Equals(), GetHashCode(), and ToString().

ToString(). 只是简单的用 属性名称/属性值 构造了一个字符串

public override string ToString()
{
StringBuilder builder 
= new StringBuilder();
builder.Append(
"{ Color = ");
builder.Append(
this.<Color>i__Field);
builder.Append(
", Make = ");
builder.Append(
this.<Make>i__Field);
builder.Append(
", CurrentSpeed = ");
builder.Append(
this.<CurrentSpeed>i__Field);
builder.Append(
" }");
return builder.ToString();
}

GetHashCode() 实现时,根据匿名类型的每个成员作为System.Collections.Generic.EqualityComparer<T>的输入,来计算hash值。

因此,如果2个匿名类型有相同的属性字段,同时每个字段的值也相同,那么生成的Hash值也就相等。

三、匿名类型的相等
static void EqualityTest()
{
// Make 2 anonymous classes with identical name/value pairs.
var firstCar = new { Color = "Bright Pink", Make = "Saab", CurrentSpeed = 55 };
var secondCar 
= new { Color = "Bright Pink", Make = "Saab", CurrentSpeed = 55 };
// Are they considered equal when using Equals()?
if (firstCar.Equals(secondCar))
Console.WriteLine(
"Same anonymous object!");
else
Console.WriteLine(
"Not the same anonymous object!");
// Are they considered equal when using ==?
if (firstCar == secondCar)
Console.WriteLine(
"Same anonymous object!");
else
Console.WriteLine(
"Not the same anonymous object!");
// Are these objects the same underlying type?
if (firstCar.GetType().Name == secondCar.GetType().Name)
Console.WriteLine(
"We are both the same type!");
else
Console.WriteLine(
"We are different types!");
// Show all the details.
Console.WriteLine();
ReflectOverAnonymousType(firstCar);
ReflectOverAnonymousType(secondCar);
}

输出结果:

Equals()      结果相等,因为它使用值来比较相等,比如,比较每个字段的值是否显等
==             结果不等,因为匿名类型没有重载 == 和 != , 这两个操作符默认情况下,比较的是对象的引用而不是成员的值。

最后,在一个程序集中(assembly),如果你定义多个字段完全相同的匿名类型对象,编译器只会生成一个匿名类型,这些对象都是该唯一的匿名类型的实例。

四、在匿名类型中定义匿名类型

// Make an anonymous type that is composed of another.
var purchaseItem = new {
TimeBought 
= DateTime.Now,

ItemBought 
= new {Color = "Red", Make = "Saab", CurrentSpeed = 55},
Price 
= 34.000};
ReflectOverAnonymousType(purchaseItem);

五、匿名类型的使用条件
应该尽量少用匿名类型,只在LINQ中使用
• You don’t control the name of the anonymous type.
• Anonymous types always extend System.Object.
• The fields and properties of an anonymous type are always read-only.
• Anonymous types cannot support events, custom methods, custom operators, or custom
overrides.
• Anonymous types are always implicitly sealed.
• Anonymous types are always created using the default constructor.