Sunday, May 06, 2007

LINQ,结构型值和类型(Structured values and types)


3.5
结构型值和类型(Structured values and types


LINQ 项目以数据为中心的程序设计格式(data-centric programming style),有些类型存在的主要目的是在结构型值之上(over a structured value)提供一个静态的“shape”(static "shape"),这胜过同时有声明(state)和行为(behavior)的完全成熟(full-blown)的对象。对它的逻辑结论(logical conclusion)作出这个假设(taking this premise),最常见的情形(is often the case)是所有的开发者当心(cares about)值的结构(structure of the value),对这个 shape 一个命名的类型(named type)的需要(the need for)是几乎无用的(is of little use)。这导致(leads to)匿名类型(anonymous types)的介绍(introduction)允许新的结构(structures)给它们的初始化(initialization)定义成“inline”。



C# 语言里,匿名类型(anonymous types)与对象初始化的语法(object initialization syntax)是一样的(is identical to),除了类型的名字(name of the type)被忽略(omitted)了。例于,考察下面的两段语句:



object v1 = new Person {
Name
= "Chris Smith", Age = 31, CanCode = false
};

object v2 = new { // note the omission of type name
Name = "Chris Smith", Age = 31, CanCode = false
};


变量 v1 v2 都指向一个内存中的对象(in-memory object),它的 CLR 类型有三个公共的属性(public properties):NameAge,和CanCode。它们的不同之处(differ in)是 v2 引用自(refers to)一个匿名类型(anonymous types)的实体。在 CLR 中(in CLR terms),匿名类型与任何其他类型没有什么不同。使得匿名类型特殊(special)的是它们在你的程序开发语言中没有特殊意义的名字(have no meaningful name)。创建一个匿名类型的实体(instances of an anonymous type)的唯一途经就是使用上面所示的语法。



为了允许变量引用匿名类型的实体仍然需要利用(benefit from)静态类型(static typing),C# 介绍 var 关键词时说它可以用于局部变量定义(local variable declarations)的类型名称(type name),例于,考察下面这段合法(legal)的 C# 3.0 程序:



关键词 var 告诉编译器从用来初始化变量的表达式的静态类型(static type)来推断(infer)这个变量的类型。在这个例子中,变量 sn b 的类型分别(respectively)是 stringint bool,这段程序和下面的程序是一样的:



string s = "Bob";
int n = 32;
bool b = true;


关键词 var 对那些类型有特殊含义名称(meaningful names)的变量是一个方便的工具(convenience),但是它对引用自匿名类型的实体的变量(instances of anonymous types)却是必需的(necessity)。



var value = new {
Name
= "Chris Smith", Age = 31, CanCode = false
};


在上面的例子中,变量 value 是一个匿名类型,它的定义与下面的 C# 伪代码(pseudo-C#:)是相等的(equivalent to):



internal class ??? {
string _Name;
int _Age;
bool _CanCode;

public string Name {
get { return _Name; } set { _Name = value; }
}

public int Age{
get { return _Age; } set { _Age = value; }
}

public bool CanCode {
get { return _CanCode; } set { _CanCode = value; }
}
}


匿名类型不能被共享于(shared)跨越(across)汇编后代码的边界(assembly boundaries),但是编译保证(ensures)在每段汇编代码中(within each assembly)对被赋予的(given)成 name/type 对(name/type pairs)的属性序列(sequence of property)最多只有一个匿名类型。



因为匿名类型常常被用在从一个现有的结构型值(an existing structured value)中选取它的一个或更多的成员的投影(projections)中,这样我们就能够简单地在一个匿名类型的初始化(initialization of an anonymous type)中从另一个值引用(reference)域(fields)或属性(properties)。这导致(results in)匿名类型获取到一个属性(property),它的名称(name),类型(type)和值(value)都拷贝自引用的属性或域(referenced property or field)。



举例来说,下面的程序通过从其他值中结合属性(combining properties)来创建一个新的结构性值(structured value):



var bob = new Person { Name = "Bob", Age = 51, CanCode = true };
var jane
= new { Age = 29, FirstName = "Jane" };

var couple
= new {
Husband
= new { bob.Name, bob.Age },
Wife
= new { Name = jane.FirstName, jane.Age }
};

int ha = couple.Husband.Age; // ha == 51
string wn = couple.Wife.Name; // wn == "Jane"


上面展示的引用域(fields)或属性(properties)的代码是与下面写出的更明显的形式(more explicit form)的一种更简单方便的语法(is simply a convenient syntax):



var couple = new {
Husband
= new { Name = bob.Name, Age = bob.Age },
Wife
= new { Name = jane.FirstName, Age = jane.Age }
};


在两种形式中(in both cases),变量 couple 都从变量 bob jane 中的 Name Age 属性获取了一份自己的 copy



匿名类型通常用于查询的 select 语句(select clause),例于,看下面的查询程序:



var expr = people.Select(p => new {
p.Name, BadCoder
= p.Age == 11
});

foreach (var item in expr)
Console.WriteLine(
"{0} is a {1} coder",
item.Name,
item.BadCoder
? "bad" : "good");


在这个例子中我们能够在类型 Person 上创建一个新的投影(projection),它正确地符合(exactly matched)我们的执行代码(processing code)所需要的形态(shape),但是仍然具有静态类型(static type)的好处(the benefits of)。





待续, 错误难免,请批评指正,译者Naven 2005-10-23

No comments: