Dir*_*oer 5 c# linq extension-methods readability
我真的很喜欢C#中的GroupBy LINQ方法.
但我不喜欢的一件事是总是调用密钥Key.
当我循环群组时,Key不会说我什么.因此,我必须查看其余的上下文,以了解Key究竟是什么.
var grouped_by_competition = all_events
.GroupBy(e => e.Competition);
foreach ( var group in grouped_by_competition )
{
[...]
// ok what is Key for kind of object? I have to look at the outer loop to understand
group.Key.DoSomething();
}
Run Code Online (Sandbox Code Playgroud)
当然你可以说它是一件小事,因为你只需要看外环.
在我看来,当你阅读它时,它仍会吃掉"大脑".因此,如果有很好的替代品需要很少的样板,我想使用它.
有一些替代方案,但它们都添加了样板代码或依赖于注释 - 我都试图省略.
选项1 - 内部循环的额外变量
var grouped_by_competition = all_events
.GroupBy(e => e.Competition)
foreach ( var group in grouped_by_competition )
{
var competition = group.Key;
[...]
competition.DoSomething();
}
Run Code Online (Sandbox Code Playgroud)
此解决方案添加了不必要的样板代码
选项2 - 额外选择
var grouped_by_competition = all_events
.GroupBy(e => e.Competition)
.Select(x => new { Competition = x.Key, Items = x } );
foreach ( var group in grouped_by_competition )
{
[...]
group.Competition.DoSomething();
}
Run Code Online (Sandbox Code Playgroud)
此解决方案添加了不必要的样板代码
选项3 - 添加关于使用Key的注释
我宁愿有富有表现力的代码,然后评论会过时.
摘要
理论上是否可以设计一种类似于匿名类功能的扩展方法?
var example = new { e.Competition };
example.Competition.DoSomething(); // property name deduced
Run Code Online (Sandbox Code Playgroud)
所以我们得到:
var grouped_by_competition = all_events
.NamedGroupBy(e => e.Competition);
foreach ( var group in grouped_by_competition )
{
[...]
group.Competition.DoSomething();
}
Run Code Online (Sandbox Code Playgroud)
理论上是否可以设计一种与匿名类功能类似的扩展方法?
不可以,因为名称必须在编译时出现,并且您建议的扩展方法将依赖于Expression在运行时检查的对象。
能够按名称引用成员的唯一方法是被引用的对象实际上具有该名称的成员。必须有一个实际的编译时名称供编译器使用。
(我在撒谎。当您使用dynamic关键字时,您告诉编译器将编译时操作推迟到运行时。这使您可以摆脱那些直到运行时才解析具有特定成员名称的类型的技巧。事实上,这是实现您既定目标的一种方法。但是,在运行时运行编译器的成本可能很高,并且会放弃编译时类型安全性,而编译时类型安全性是 C# 和类似静态类型语言的标志性功能。dynamic关键字在某些情况下是一个重要的功能,但我不会说这个特定的用例证明了成本的合理性。)
就我个人而言,我不认为这个名字Key有问题。在一个非常重要的方面,它非常具有表现力:也就是说,它告诉我,我正在处理一个分组的关键。如果我想了解更多信息,它的类型通常足以进一步详细说明,并且将鼠标悬停在它上面即可立即获得。
但是,不同的人有不同的行程。如果目标是拥有一个不同于 的命名成员Key,那么您的匿名类型投影恕我直言是您将获得的最佳选择。GroupBy()请注意,您可以通过使用允许您直接投影每个组的重载来提高简洁性,而不是使用以下Select()方法:
var grouped_by_competition = all_events
.GroupBy(e => e.Competition, (k, g) => new { Competition = k, Items = g });
Run Code Online (Sandbox Code Playgroud)
所以,另一件事:当我写到“能够通过名称引用成员的唯一方法是,被引用的对象实际上具有该名称的成员”时,有一点挥手的感觉那里。也就是说,真正重要的是编译器在编译时知道该名称。
通常,这意味着确实存在一个具有该名称的命名成员的类型。但该规则有一个例外,最近添加到 C# 中,即使用ValueTuple. 这样,您就可以隐式地给出一个名称,而无需引入实际的新类型。编译器只是在本地方法中跟踪它,并将其视为实际类型。
在这种特定情况下,元组语法并没有真正改进匿名类型语法。它有点短,但也不是很多:
var grouped_by_competition = all_events
.GroupBy(e => e.Competition, (k, g) => (Competition: k, Items: g));
Run Code Online (Sandbox Code Playgroud)
它确实具有使用该类的潜在性能优势ValueTuple;作为一种值类型,使用它可以显着减少 GC 开销。但并非所有场景都会从中受益。