C# 7 中的 C# 匿名类型是否多余

Are C# anonymous types redundant in C# 7

自从 C# 7 引入值元组以来,是否存在它们比元组更适合的有意义的场景?

例如下面一行

collection.Select((x, i) => (x, i)).Where(y => arr[y.i].f(y.x)).ToArray();

生成以下行

collection.Select((x, i) => new {x, i}).Where(y => arr[y.i].f(y.x)).ToArray();

多余。

哪个用例比另一个更好用(出于性能原因或优化原因)?

显然,如果需要超过六个字段,则不能使用元组,但是有没有更细微的差别?

匿名类型和 C# 7 元组之间存在各种差异,在某些情况下可能会或可能不会使一个比另一个更合适:

  • C# 7 元组是 ValueTuple<>。这意味着它们是 值类型 而匿名类型是引用类型。
  • 元组允许在编译时进行静态类型化,因为它们是一种可以显式表达的类型。因此,您可以将它们用作方法参数、return 类型等。
  • 匿名类型的成员是存在于该类型上的实际属性。元组项是 字段 .
  • 匿名类型的属性具有实际名称,而元组中的字段仅命名为 ItemN(对于数字 N)。标签只是编译器主要使用的元数据信息,不会与实际的元组对象一起保存。
  • 因为创建匿名类型实际上在幕后创建了一个类型,所以您对它们具有一定程度的类型安全性。由于元组只是具有应用类型参数的通用容器,因此您对它们没有完全的类型安全。例如 size(int, int) 元组将完全兼容 position(int, int) 元组,而匿名类型完全关闭。
  • 正如 Jon Skeet 提到的,C# 7 元组语法在表达式树中是 currently not supported

@poke 的当前回答是正确的,并指出了元组和匿名类型之间的区别。我将讨论为什么您仍然会使用它们或更喜欢其中一个。

有两个新的 c# 7 特性可以淘汰匿名类型。 ValueTuples and Records.

您不使用匿名类型的主要原因是

  • 您不能在全局范围内使用匿名类型,它们只有在本地使用时才是类型安全的。不是本地的,您必须将其视为 dynamic 具有显着性能开销的对象

您更喜欢元组而不是匿名类型的原因。

  • 它们在所有地方都是类型安全的。 (不考虑命名)

  • 它们可以用作方法参数、类型参数、字段以及几乎所有地方。 (是的,我说的差不多了,有些地方需要采用元组,这是时间问题。)

  • 因为它们可以用作类型参数,您可能更喜欢将轻量级参数集包装在单个参数中。喜欢 Stack<(min, mid, max)>

  • 你可以在你觉得合适的时候更改项目命名,在通用上下文中名称 item 可能会满足,在更具体的上下文中你也需要更具体的名称,比如 car

  • 它们是隐式可转换的,int, int 可以分配给 (int, long) 而无需显式转换。

  • 它们在 Deconstruct 中使用。这给语言带来了很多语法糖。

  • 你可以有多个赋值和声明,比如(int x, int y) = (0, 1)

拥有所有这些功能,还有一个原因可能会让您更喜欢匿名类型而不是元组。

  • 匿名类型是引用类型,而元组是值类型。

但是如果你想全局使用匿名类型怎么办?您更喜欢动态对象还是静态类型对象?

传入记录功能再次击败匿名类型。使用记录,您可以用简短、简洁和方便的方式定义 class。没什么大不了的。只有一行

public class Point(X, Y);

无处不在的类型安全,而且您还掌握了引用类型。这两个新特性带来了击败匿名类型的一切。

请注意,记录尚未添加,我们只需要等待。

仅剩下的匿名类型的实际使用将是

  • 它们仍然作为向后兼容的功能

  • 当您在本地使用匿名类型时,它们可以在 Linq 查询中使用。因此我并不是说匿名类型是多余的。

正如我所说,ValueTuples 还不兼容所有组件。这只是时间问题,但这就是未来的样子。

足够的论据。在我看来,匿名类型的使用变得很少,老程序员可能仍然习惯在 Linq 中使用匿名类型。