关于c#:为什么隐式属性名称只能在匿名对象中使用?

Why do implicit property names only work in anonymous objects?

限制是什么

1
2
3
4
5
6
7
8
public class A
{
     public string Stuff {get;set;}
}

...

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

那不管用。你必须添加

1
2
3
{ Stuff = x.Stuff }

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

但这是可行的。它创建了一个与类A定义非常相似的anon类。

从概念上讲,我看不出这里发生了什么大的变化。有人发光吗?


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

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

That doesn't work. You have to add

这是对象初始值设定项。这是通过调用对象的默认构造函数,然后将属性名与值(即:Stuff = x.Foo匹配)来实现的,它实际上只是匹配属性的快捷方式,因此语法实际上只是用于:

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

现在,我假设编译器团队可以假定一个没有左侧的初始化语句应该搜索一个匹配的属性,其中名称匹配并且类型可以隐式转换,但是我怀疑如果或者当它被语言团队。一般来说,C在语法上相当明确,这将在需要两个单独匹配(name+type)的方式上稍微放宽这一点,并且在许多情况下都不明显。因为您在这里使用的是公共API(A),所以在任意一侧(A或定义为"x"的任何类型)重构也很容易完全破坏它。

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

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

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

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

这是在做完全不同的事情——在这里,您正在初始化一个匿名类型,并让编译器为您完全确定类型名和类型。我怀疑这是确定为"安全的",因为您从未真正使用过公共API——匿名类型实际上不应该"泄漏"出定义它的方法。在这种情况下,重构更改属性名和有效更改值等的风险会大大降低,并与单个方法隔离,从而使这种"自动"命名功能总体风险更低。另外,这里没有一个简单的替代方法,因为您不能在匿名类型上定义构造函数,所以在这种情况下,没有一个简单的方法来使用简洁的语法。这增加了收益而不会带来很多风险。


一个可能的理由是:如果允许对实际类型进行隐式属性分配,则存储库项的更改(即,将x.Stuff重命名为x.Other)将导致非常令人惊讶的编译时错误,因为新属性不再与a.stuff匹配。