繁体   English   中英

对LINQ参数感到困惑

[英]Confused about LINQ parameters

我正在尝试了解 LINQ 并对使用它充满信心。 我正在努力解决的是要求的参数。 例子:

var sortedWords = words.OrderBy(a=>a.Length)

words是一个数组集合。 OrderBy的智能感知 说:

Func<string, TKey> keyselector

一个func执行一个方法,一个string是值, TKey是一个键。

在示例http://msdn.microsoft.com/en-us/vcsharp/aa336756.aspx#thenBySimple ( ThenBy - Comparer) 中,我们通过a => a.Length来比较长度。 我理解这种语法,但这与智能感知的要求有什么关系?

由于所有 generics,我倾向于发现方法签名和智能感知不可读。

谢谢。

如果您了解 .NET/C# 中lambda 表达式的性质,则该类型(由 Intellisense 显示)是有意义的。 否则,对于新人来说,确实有点奇怪。 首先考虑 keySelector 的类型Func<TSource, TKey>只是一个委托。 在 C# 3.0 之前,您可以通过将委托作为参数传递来调用此类方法,例如:

IEnumerable<string> sortedWords = words.OrderBy(new Func<string, int>(mySelectorMethod));

其中 mySelectorMethod 是一个普通方法的名称,它接受一个字符串作为参数并返回一个int (As a side point, I suppose you could use anonymous delegates, but let's not go there for now.) Also, note that this example is purely illustrative, as LINQ is almost always used with .NET 3.5/C# 3.0 (though I believe it可以与 .NET 2.0/C# 2.0 中的一个/两者一起使用 - 如果我错了,请有人纠正我)。 从 C# 3.0 开始,可以将方法内联定义为 lambda 表达式,这些表达式旨在用于此类情况。 如果您想获得正确的介绍,请阅读有关 lambda 表达式(上面链接)的 MSDN 文章,但在这里我将简单地描述在此特定上下文中的使用。 当您使用 state 时,您的代码(在 C# 3.0 中)类似于以下内容:

var sortedWords = words.OrderBy(a => a.Length);

表达式的a => a.Length部分是lambda 表达式,它实际上只是声明 function 内联的简写。 lambda 表达式的语法大部分都很简单; 在 => 的左侧,指定了 arguments,通常采用(arg1, arg2, arg3)形式,但由于在这种情况下只有一个,因此您可以省略括号。 => 的右侧是作为 function 的返回值的表达式(更准确地说是 lambda 表达式)。 或者,您可以在 { 和 } 中使用 return 语句将实际代码括起来,尽管这通常是不必要的。 我相信 C# 编译器所做的是将传递给 OrderBy 的参数识别为 lambda 表达式,然后将其编译为 function 并为您创建和传递委托。 请注意,lambda 表达式也可以转换为System.Linq.Expressions.Expression对象(可访问的表达式树)而不是委托,但这是一种不太常见的用法。 无论如何,这里的幕后发生了很多事情,但希望这至少应该澄清为什么类型是Func<TSource, TKey>以及它与 lambda 表达式的关系。 正如我所说,如果您想更深入地了解 LINQ/lambdas/delegates,请阅读 MSDN...

a => a.Length

我理解这种语法,但这与智能感知的要求有什么关系?

这段代码是一个 lambda 表达式。 lambda 表达式是生成匿名方法(在这种情况下)或 System.Linq.Expressions.Expression 的便捷方式。 让我们按部分分解它。

  • 最引人注目的特性是=> ,它将参数与方法体分开。
  • =>的左侧,有一个符号: a 这是我们匿名方法的参数声明。 编译器知道我们正在调用 OrderBy(),并且 OrderBy 需要一个Func<string, object> 此类 function 的参数是字符串,因此编译器确定a必须是字符串。 程序员唯一需要提供的是名字。
  • =>的右侧,有方法体。 由于这是单行代码,因此隐含了return关键字。 IDE 提供针对a作为字符串的智能感知,允许您使用 Length 属性。

现在,考虑这个 C# 2.0...

IEnumerable<string> sortedWords = 
  Enumerable.OrderBy(words, delegate(string a) {return a.Length;});

与 C# 3.0

IEnumerable<string> sortedWords = words
  .OrderBy(a => a.Length);

我认为 IntelliSense 实际上非常有用,特别是对于将Func<..>类型作为参数的泛型方法,因为您可以看到类型和类型指导您了解该方法可能会做什么。

例如, OrderBy的 arguments 是IEnumerable<string>作为 'this' 参数,这意味着我们有一些包含字符串集合的输入。 第一个参数keySelector有一个类型Func<string, TKey> ,这意味着它是您提供的一些 lambda 表达式,它指定如何从string获取TKey

这已经表明该方法可能会枚举集合中的所有项目(字符串),并且它可以使用keySelector从集合中的每个元素获取TKey类型的值。 TKey这个名字已经表明它将使用这个值来比较使用这个计算出来的键的元素(字符串)。 但是,如果您查看采用IComparer<TKey>的其他重载,那么您可以确定这一点 - 此参数指定有关如何比较TKey类型的两个值的更多详细信息,因此 function必须使用此比较元素钥匙。

...这种对类型的思考需要一些时间来适应,但是一旦你学会了它,它就会非常有帮助。 它在“功能”风格的代码中更有用,它经常在 C# 3.0 中使用大量的 generics 和 lamdba 表达式(以及类似的功能语言,如 Z629B160731F33947EAC814BF3E58 或其他)

老实说,我从不真正担心 Intellisense。 在我的 Linqage 中,我很早就搞砸了。 随着我花更多时间在 generics 和表达式上,它开始变得有意义,但在此之前我只是在语法上抽筋。

它想要的是一个 lambda 表达式,它告诉 Linq 为了对您的集合进行排序而查找什么。

我觉得你,我的兄弟,坚持下去,很快就会有意义。

OrderBy()接受 function 的委托,该委托接受单个参数(在您的情况下为string )并返回替换TKey的类型的值。 可能是参数类型(字符串)已经确定,因为您在IEnumerable<string>上调用了该方法,但委托类型只会在它从 lambda 表达式推断出来之后被解析为Func<string, int >完全指定(即a => a.Length )。 如果您没有向解析器提供任何关于您想要什么作为排序键的线索,它只会在 IntelliSense 中显示TKey ,直到它可以确定预期的类型。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM