对LINQ参数感到困惑

时间:2009-03-10 23:01:38

标签: c# linq

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

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

words是一个数组集合。 OrderBy的intellisense说:

Func<string, TKey> keyselector

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

在示例http://msdn.microsoft.com/en-us/vcsharp/aa336756.aspx#thenBySimpleThenBy - Comparer)中,我们通过说a => a.Length来比较长度。我理解语法,但这与intellisense要求的内容有什么关系?

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

感谢。

5 个答案:

答案 0 :(得分:6)

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

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

其中mySelectorMethod是普通方法的名称,该方法将字符串作为参数并返回 int 。 (作为一个侧面点,我想你可以使用匿名委托,但是现在不要去那里。)另外,请注意这个例子纯粹是说明性的,因为LINQ几乎总是与.NET 3.5 / C#3.0一起使用(虽然我相信它可以与.NET 2.0 / C#2.0中的任何一个一起使用 - 如果我错了,有人会纠正我。从C#3.0开始,方法可以内联定义为lambda表达式,这些表达式旨在用于这些情况。如果你想得到一个正确的介绍,请阅读有关lambda表达式(上面链接)的MSDN文章,但在这里我将简单描述在这个特定上下文中的用法。正如您所说,您的代码(在C#3.0中)类似于以下内容:

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

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

答案 1 :(得分:5)

a => a.Length
  

我理解语法,但这与intellisense要求的内容有什么关系?

这段代码是lambda表达式。 lambda表达式是生成匿名方法(在本例中)或System.Linq.Expressions.Expression的便捷方式。让我们按部分分解。

  • 最明显的功能是 =&gt; ,它将方法体中的参数分开。
  • =&gt; 的左侧,有一个符号: a 。这是我们的匿名方法的参数声明。编译器知道我们正在调用OrderBy(),而OrderBy需要Func<string, object>。此类函数的参数是字符串,因此编译器确定 a 必须是字符串。程序员唯一需要提供的是名称。
  • =&gt; 的右侧,有方法正文。由于这是一行内容,因此隐含了 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);

答案 2 :(得分:1)

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

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

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

......这种关于类型的思考需要一些时间来习惯,但是一旦你学会了它,它就会非常有用。它在“功能”代码风格中更有用,它通常在C#3.0中使用大量泛型和lamdba表达式(在F#或其他函数语言中类似的东西)

答案 3 :(得分:0)

说实话,我从不真正担心智能感知。在我的Linqage早期让我搞砸了。因为我花了更多的时间来使用泛型和表达式,所以它开始有意义,但直到那时我才开始使用语法。

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

我觉得你,我的兄弟,在那里,很快就会有意义。

答案 4 :(得分:0)

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