Linq 查询中的匿名类型与元组,性能注意事项

Anonymous type vs tuple in Linq query, performance considerations

这个问题专门针对内存数据,与查询翻译框架无关(例如,与 Entity Framework 以及它如何转录某些 Linq 查询无关)。

假设我们有一个 IEnumerable 包含类型:

class Exemplar 
{
    public Guid UniqueId { get; set; }
    public string Name { get; set; }
    public string[] FriendNames { get; set; }
}


var exampleData = new List<Exemplar>(); // pretend I'm populated

我们的业务规则类似于:

我习惯于编写使用匿名类型作为链中中间结构的 Linq 查询。例如:

var invalidExemplars =
    exampleData
        .Select(x =>
            new
            {
                Id = x.UniqueId,
                InvalidNames = x.FriendNames.Where(n => exampleData.All(d => d.Name != n)).ToArray()
            })
        .Where(x => x.InvalidNames.Any());

// added for completion, maybe irrelevant to the question
if (invalidExemplars.Any())
{
    Console.WriteLine(string.Join(Environment.NewLine, invalidExemplars.Select(x => $"{x.Id}: [{ string.Join(",", x.InvalidNames)}]")));
}

但现在有了 C# 7,我们可以使用新的元组 shorthand 而不是匿名类型:

var invalidExemplars =
    exampleData
        .Select(x =>
        (
            Id: x.UniqueId,
            InvalidNames: x.FriendNames.Where(n => exampleData.All(d => d.Name != n)).ToArray()
        ))
        .Where(x => x.InvalidNames.Any());

我的问题是中间匿名类型与中间元组之间是否存在任何性能差异,如果有,它们是什么?

有什么理由(个人偏好除外)选择其中之一作为中介

匿名类型值元组有一些非常细微的区别。

  • 平等
  • 存储 - 堆/堆栈
  • 参数命名
  • 表达式树
  • 语法 - 构造语法、解构语法等
  • 用法 - 如何将它们用作方法参数等

因为这个问题是关于中介使用的,所以 Value Tuple 很可能会被堆分配,因为 LINQ, 表达式树ORMS 不在等式中。那么除了相等性和语法之外几乎没有什么区别,另外对性能的影响将相当不明显。所以答案真的归结为选择你最喜欢的。


其他资源

Choosing between anonymous and tuple types

权衡

You might want to always use ValueTuple over Tuple, and anonymous types, but there are tradeoffs you should consider. The ValueTuple types are mutable, whereas Tuple are read-only. Anonymous types can be used in expression trees, while tuples cannot. The following table is an overview of some of the key differences.

主要区别

Name Access modifier Type Custom name Deconstruction Expression tree
Anonymous types internal class ✔️ ✔️
Tuple public class ✔️
ValueTuple public struct ✔️ ✔️

性能

Performance between these types depends on the scenario. The major impact involves the tradeoff between allocations and copying. In most scenarios, the impact is small. When major impacts could arise, measurements should be taken to inform the decision.


进一步阅读