2

有什么限制

public class A
{
     public string Stuff {get;set;}
}

...

repository.GetAll().Select(x=> new A { x.Stuff });

那是行不通的。你必须添加

{ Stuff = x.Stuff }

repository.GetAll().Select(x=> new { x.Stuff });

但这有效。它创建了一个与 A 类定义非常相似的匿名类。

从概念上讲,我认为这里发生的事情没有太大区别。有人阐明了吗?

4

2 回答 2

3

简短的回答——C# 编译器和语言团队没有以这种方式实现它——他们要么没有想到(不太可能),要么认为这不是一个好主意......

repository.GetAll().Select(x=> new A { x.Stuff });

那是行不通的。你必须添加

这是一个对象初始化器。这通过在对象上调用默认构造函数,然后将属性名称与值匹配,即:Stuff = x.Foo,并且实际上只是匹配属性的快捷方式,因此语法实际上只是“速记”:

A tmp = new A();
tmp.Stuff = x.Stuff;

现在,我想编译器团队可以假设等式上没有左侧的初始化语句应该搜索名称匹配类型可隐式转换的匹配属性,但我怀疑这将落入“与坏主意列表调情“如果或何时由语言团队讨论。一般来说,C# 的语法相当明确,这会稍微放松一下,需要两个单独的匹配项(名称 + 类型),并且在许多情况下并不明显。由于您在此处使用公共 API ( A),因此在任一侧进行重构 (A或任何类型的 "x"

最后,这也不是必需的 - 如果您希望以这种方式构造 A 的实例,只需添加一个带有重载的构造函数(在任何情况下这在许多方面都更安全),然后使用:

repository.GetAll().Select(x=> new A(x.Stuff));

这使得意图和含义非常明确,并消除了脆弱的可维护性。

repository.GetAll().Select(x=> new { x.Stuff });

这是在做一些完全不同的事情——在这里,您正在初始化一个匿名类型,并让编译器为您完全确定类型名称和类型。我怀疑这被确定为“安全”,因为您从未真正使用过公共 API - 匿名类型不应该真正从定义它的方法中“泄漏”出来。在这种情况下,重构更改属性名称和有效更改值等的风险会大大降低并隔离到单个方法,这反过来又使这种“自动”命名功能总体上降低了风险。此外,这里没有一个简单的替代方案,因为您无法在匿名类型上定义构造函数,因此在这种情况下,没有一种简单的方法来获得简洁的语法。

于 2012-05-23T17:37:57.613 回答
1

一种可能的推理:如果允许对真实类型进行隐式属性分配,而不是更改存储库项(即x.Stuff重命名为x.Other),则会在非常令人惊讶的地方导致编译时错误,因为新属性不再匹配 A.Stuff。

于 2012-05-23T17:26:43.423 回答