2010-08-18 75 views
2

这是根据是否有一些匹配的ID来返回布尔值。IQueryable.Where()实际发生了什么?

from t in getAll 
select new Result 
{ 
...    
    bool DetailsAvailable = 
     (db.SaveTrackings.Where(s => s.BundleID == t.bundleID 
            && s.UserID == t.userID) 
         .Count() > 0) ? true : false; 
} 

这就是我想明白了:.Where()将返回所有匹配的ID的条目,然后.Count()只是看到究竟有多少。我只是觉得我有一半明白我们需要s

我知道从这段代码中可以期待什么,因为它已经被使用了,我只是不明白它是如何工作的,MSDN中的一些文档使用了一些令我困惑的术语。

所有lambda表达式使用拉姆达 运算符=>,它读作 “去 于”。 lambda 运算符的左侧指定输入 参数(如果有的话),并且右侧 包含表达式或语句 块。 lambda表达式x => x * x被读取为“x转到x次x”。

所以怎么了,我想明白了什么我的代码意味着在此基础上,.Where(s“变为” s.BundleID == t.BundleID ...),所以这里发生了什么? “去”是什么意思?是否将s中的每个ID与t中的每个ID进行比较?我怎么理解为什么它被称为“去”和究竟发生了什么?

然后它变得更加扑朔迷离......

=>运算符具有相同的优先级 如赋值(=),是 右结合。

Lambdas用于基于方法的LINQ 查询作为标准查询的参数 运算符方法(如Where)。

当您使用基于方法的语法来调用 Where方法在 枚举类(如你在LINQ做 对象和LINQ to XML)的参数 是委托类型System.Func。拉姆达表达式是创建 委托的最方便的方式。

什么是代表类型System.Func<T, TResult>以及它是如何使用此“去”运算符创建的?

我不能只是使用代码,因为我知道它的工作,我需要了解如何/为什么。

+2

如果您真的只需要一个true或false,那么使用Any函数而不是where + count可能更有效?一旦一个项目为真,db.SaveTrackings.Any(相同的谓词)将立即返回true。 – 2010-08-18 16:03:08

+0

@John谢谢,如果我只能理解这个整个委托/ lambda事件发生了什么,试图让我的头在 – BigOmega 2010-08-18 18:01:44

+0

位,它会花一点时间,然后它只会“点击”。最简单的方法就是将它们视为没有名字的迷你函数。语法可能会有点奇怪,特别是没有参数...()=> {等等等等等等等等等等等等。 WTH是那样的!:D – 2010-08-19 15:54:36

回答

2

也许这将有助于看到这个功能通过手工来实现:

using System; 
using System.Collections.Generic; 

namespace CSharpSandbox 
{ 
    class Program 
    { 
     static IEnumerable<T> Where<T>(IEnumerable<T> input, Func<T, bool> predicate) 
     { 
      foreach (T item in input) 
      { 
       if (predicate(item)) 
        yield return item; 
      } 
     } 

     static void Main(string[] args) 
     { 
      int[] numbers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 
      IEnumerable<int> evens = Where(numbers, n => n % 2 == 0); 
      foreach (int even in evens) 
      { 
       Console.WriteLine(even); 
      } 
     } 
    } 
} 

构建体name => someEvaluation创建匿名函数,由以下部分组成:

  • name是一个简单的参数的名称,它的类型是从它的使用推断。您需要一个名称,以便您可以引用该函数中传递的参数。
  • =>是您的匿名函数体的开始,正文的范围是单个表达式。
  • someEvaluation是由单个表达式组成的匿名函数的主体。

在我们的情况下,Func<T, bool>限定函数,它接受T类型的单个参数,并返回bool类型的输出。 (如果我们使用Func<T, U, bool>,我们会采取T型和U的两个输入,并返回一个bool。在Func定义的最后一个类型参数的返回值。)

您可以准确地调用的Func实例作为你调用任何其他函数。如果函数使用参数,则按照预期将它们传入,参数将绑定到您定义的变量名称。当你调用该函数时,控制流将跳转到你的函数中并评估其结果。

原则上,您不需要匿名创建Func。您可以通过任何具有兼容类型签名的功能,例如:

static bool IsEven(int n) 
    { 
     return n % 2 == 0; 
    } 

    static void Main(string[] args) 
    { 
     int[] numbers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; 
     IEnumerable<int> evens = Where(numbers, IsEven); 
     foreach (int even in evens) 
     { 
      Console.WriteLine(even); 
     } 
    } 

该程序产生相同的输出。事实上,在幕后,语法name => expression是语法糖;当它被编译时,C#将生成一个带有隐藏名称的私有函数,并将其转换为上面的格式。

+0

也许这也会有所帮助:http://stackoverflow.com/questions/2294053/explaining-functional-programming-to-object-oriented-programmers-and-less-technic/2294279#2294279 – Juliet 2010-08-18 18:29:12

+0

等一下。用你的第一个例子,你写出了一个函数。这仅仅是为了证明发生了什么,或者这是否真的如何实现?因为我得到了正在发生的事情,我只是不明白。例如,如果我做了一个cout >>计算机告诉显卡将文本吐出到我的显示器上。但是我不知道这些事情是怎么发生的,我只知道他们工作。 – BigOmega 2010-08-19 23:39:34

+0

@Ryan:是的,上面的函数真的*是*你如何实现Where函数。它不清楚你不了解哪部分。对于它的价值,大多数C#都充满语法糖,偶尔可能会掩盖底层实现细节。一个包含'yield return whatever'的函数被转换为一个实现'IEnumerable '的类,它本身就是一个状态机,每次调用它的枚举器的MoveNext()函数时它都会转移到下一步。 (...) – Juliet 2010-08-20 00:25:46

2

如果有帮助,请将s作为SaveTracking类型的变量。它正在迭代您收集/表中的每个s,并测试其BundleID的值。

t是一样的想法 - 就像它遍历所有getAll的返回集合。

这就像SQL伪代码:

SELECT * FROM SaveTracking INNER JOIN GetAll 
    ON BundleID AND UserID 

对于正在发生的事情与lambda表达式,检查出Jon Skeet's book C# In Depth有更深入的技术说明。第9章,第230页。我发现这本书很有帮助。

+0

这虽然没有帮助,但因为我已经理解了,并且有'像这样想'这个例子不是我所需要的,我想知道计算机究竟是做什么而不是做什么行为是 – BigOmega 2010-08-18 18:03:36

0

Lambda表达式只是缩短了代码的方式,但它确实一模一样的事情,宣称对应委托类型System.Func<T, TResult>

我相信C#你兰巴转换为方法在后台运行的方法编译和它看起来像这样:

bool LambdaExpression(YourType s) 
{ 
    return s.BundleID == t.bundleID && s.UserID == t.userID; 
} 
相关问题