【问题标题】:Can someone explain this Linq Query?有人可以解释这个 Linq 查询吗?
【发布时间】:2009-10-02 06:59:27
【问题描述】:

我从 msdns 101 linq 示例中得到了这个 linq 示例:

public void Linq12() {
    int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };

  var numsInPlace = numbers.Select((num, index) => new {Num = num, InPlace = (num ==     
  index)});

    Console.WriteLine("Number: In-place?");
    foreach (var n in numsInPlace) {
        Console.WriteLine("{0}: {1}", n.Num, n.InPlace);
    }
}

这是我的问题:

  1. 什么是 (num, index) 部分?这些可以称为 a,b 之类的名称吗?可以有多少我想要的?

  2. 编译器如何确定匿名类型将是什么类型?

  3. => 有什么用?

  4. 必须始终至少有一个参数。例如,在下面的 linq 查询中是 n 个参数或此选择与另一个不同 (Select(num,index))

    int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
    
    var numsPlusOne =
        from n in numbers
        select n + 1;
    }
    

【问题讨论】:

    标签: c# linq


    【解决方案1】:

    1) 这些是传递给Func<TSource, Int32, TResult> 的参数,此Enumerable.Select 重载使用。

    发生的事情是编译器会自动创建一个 lambda,该 lambda 从您的枚举中传递一个“<T>”,并将它的索引传递给您正在生成的函数。您将其命名为“num”和“index”,“num”是数组中的整数,“index”是数组的索引。您可以将它们命名为任何名称,但它们必须存在于 Select 方法所使用的 Func 中(在这种情况下,总会有两个,而第二个将是一个 int)。

    2) 编译器为您创建一个新类型。匿名类型就是这样 - 生成的匿名类型具有与您在其中分配的类型相对应的属性,在这种情况下,一个 int (Num) 和一个 bool (InPlace)。类型由设置的内容决定。

    3) 这是Lambda Operator。它允许您创建一个 lambda 表达式,它是一个内联定义的函数,没有返回单个值的名称。

    4) 在第二种情况下,LINQ 调用Select 的重载,它采用Func<TSource,TResult>,因此您只有一个参数。 Enumerable.Select 有两个版本。

    【讨论】:

    • 太棒了!感谢您的精彩解释。我将不得不对其进行更多解析。如果您明白我的意思,有时这些答案会带来新的问题。
    • @Xaisoft:等到你遇到闭包(再次)
    • 大声笑,我实际上还有一个关于查询的问题,并将更新我的帖子。
    • 我刚刚回答了你的另外两个问题。
    【解决方案2】:

    这些可以叫什么吗?

    是的

    我想要多少都可以吗?

    没有。这是一个函数的签名,它必须与 IEnumerable<T>.Select() 重载之一的选择器参数相匹配。来自文档:

    选择器的第一个参数表示要处理的元素。 selector 的第二个参数表示该元素在源序列中的从零开始的索引。

    .

    编译器如何确定匿名类型将是什么类型?

    现场构成了一种新的类型。嗯,有点。编译器组成一个新类型,即使在那里它偶尔也会重用组成的类型。

    => 是干什么用的?

    这是 lambda 运算符(也称为“wang”运算符。真的。)。它告诉编译器你正在构建一个 lambda 表达式(基本上是一个内联函数)。

    必须始终至少有一个参数。

    在这种情况下,是的。您必须创建一个与选择器参数所期望的类型相匹配的表达式,以调用Select() 方法。在其他情况下,没有。你当然可以这样做:

    Func<string> x = () => string.Empty;
    

    是一个参数或者这个选择与另一个不同

    编译器会将选择代码转换为使用与选择扩展方法相同类型的 IL。但是,这是一个不同的选择,因为它使用了不同的重载。

    【讨论】:

      【解决方案3】:
      1. 是的,它们可以称为 a 或 b;它们是委托中使用的参数。

      2. 编译器只生成一个匿名类型;那是类型。

      【讨论】:

      • 是的,它给了它一个名字;但这是一个实现细节。
      【解决方案4】:

      1
      (num, index) 是 lamda 表达式中的参数。它采用以下形式:

      (parameters) => expression
      

      如果只有一个参数,括号可以省略:

      parameter => expression
      

      您可以将参数命名为任何您喜欢的名称,但不会与范围内的其他变量冲突。

      lambda 表达式中可以有任意数量的参数(甚至为零),但是当您在调用方法时使用它时,它必须与方法所期望的委托的签名相匹配。

      2
      编译器不会确定匿名类的类型,它会创建一个包含已设置属性的新匿名类。

      【讨论】:

      • 所以必须始终至少有一个参数。
      • @Xaisoft:不,你可以有零个参数,像这样:() => 表达式。
      【解决方案5】:
      使用

      (num, index) 是因为 lambda 表达式有两个参数。 您应该可以将这些称为任何您想要的名称,但是将第二个称为“索引”以提醒它所代表的内容很有用。 以Select为例,我相信你只能使用一两个参数。

      恐怕我无法真正解决您的第二个问题。

      编辑: 关于您的新问题,“=>”只是 lambda 表达式的语法。 this 左边的表达式代表参数,右边的表达式代表函数的主体。

      据我所知,这是:

      var numsPlusOne =
       from n in numbers
       select n + 1;
      

      和这个是一样的:

      var numsPlusOne = numbers.Select(n => n + 1);
      

      区别仅在于语法(如何编写)。

      【讨论】:

      • 感谢您的转换。这有帮助。
      猜你喜欢
      • 2012-04-19
      • 2011-07-14
      • 2022-10-07
      • 2011-07-31
      • 1970-01-01
      • 2011-01-17
      • 2013-01-09
      • 2021-01-06
      • 1970-01-01
      相关资源
      最近更新 更多