1

我对以下内容感到困惑。

我一直在使用以下格式在我的项目中使用 LINQ:

var query =     
    from obj_i in set1
    join obj_j in set2 on 
        new { 
          JoinField1 = obj_i.SomeField1,
          JoinField2 = obj_i.SomeField2,
          JoinField3 = obj_i.SomeField3,
          JoinField4 = obj_i.SomeField4
        } 
        equals 
        new { 
          JoinField1 = obj_j.SomeOtherField1,
          JoinField2 = obj_j.SomeOtherField2,
          JoinField3 = obj_j.SomeOtherField3,
          JoinField4 = obj_j.SomeOtherField4
        }

但最近有人告诉我,以下也是编写 LINQ 查询的“另一种方式”。

var query =     
    from obj_i in set1
    join obj_j in set2 on       
    obj_i.SomeField1 = obj_j.SomeOtherField1 and
    obj_i.SomeField2 = obj_j.SomeOtherField2 and
    obj_i.SomeField3 = obj_j.SomeOtherField3 and
    obj_i.SomeField4 = obj_j.SomeOtherField4

据我了解,使用 single是错误的(特别是在 by不适用=的情况下,因为您需要使用,但 using也是错误的,因为正确的关键字将是如果您被允许使用任何东西,但在这种情况下。==equalsand&&equals

我可以理解 where 子句中&&and的使用==,这使得上面的代码可以使用更加突出,因为它甚至不编译。

我错过了什么吗?如果是这样,您能否指出我可以在哪里学习这种编写 LINQ 的替代方法?

4

1 回答 1

4

但最近有人告诉我,以下也是编写 LINQ 查询的“另一种方式”。

不,您显示的第二种语法不正确。试试看,你会发现它不能编译。

Linq 查询理解语法中的join子句被转换为对Join扩展方法的调用。例如,这个查询:

var query =
    from x in a
    join y in b
    on x.Foo equals y.Bar
    select Baz(x, y);

被翻译成:

var query = a.Join(b, x => x.Foo, y => y.Foo, (x, y) => Baz(x, y));

所以可以看到左右部分equals对应Join方法的不同参数:左边部分选择第一个源的join key,右边部分选择第二个源的key。然后将这些键相互匹配以执行连接。这是重要的部分:该on子句没有指定自由格式的连接条件,它指定了如何提取每一侧的连接键。所以左右键选择器明确分开;您显示的第二种语法不起作用,因为无法为任一源提取完整的关键信息:连接只能通过评估 each 的连接条件来执行(x, y),这是一个O(n²)操作而不是(粗略的)O(n)操作。

但是,有时您需要比 equi-join 所能提供的更大的灵活性;在这种情况下,您可以使用交叉连接并过滤结果:

var query =
    from x in a
    from y in b
    where x.Foo == y.Bar
    select Baz(x, y);

或者在你的情况下:

var query =     
    from obj_i in set1
    from obj_j in set2
    where obj_i.SomeField1 == obj_j.SomeOtherField1
    &&    obj_i.SomeField2 == obj_j.SomeOtherField2
    &&    obj_i.SomeField3 == obj_j.SomeOtherField3
    &&    obj_i.SomeField4 == obj_j.SomeOtherField4;
于 2012-05-21T08:30:20.803 回答