为什么这个多linq连接代码不起作用?

时间:2017-04-29 02:17:14

标签: c# linq join

我在c#-LINQ中创建了一个简单的多连接代码。

但有些问题就是这样发生的。

样本1)很好用。结果是[1,2]。

public class tempClass1
    {
        public int i1;
        public int i2;
    }

    public class tempClass2
    {
        public int i3;
        public int i4;
    }

    public class CompareClass
    {
        public int compare1;
        public int compare2;
    }

    List<tempClass1> tempList1 = new List<tempClass1>();
    List<tempClass2> tempList2 = new List<tempClass2>();


    public MainWindow()
    {
        InitializeComponent();            

        try
        {
            tempList1.Add(new tempClass1() { i1 = 1, i2 = 2 });
            tempList1.Add(new tempClass1() { i1 = 3, i2 = 4 });
            tempList1.Add(new tempClass1() { i1 = 5, i2 = 6 });

            tempList2.Add(new tempClass2() { i3 = 1, i4 = 2 });

            var result = from t1 in tempList1
                         join t2 in tempList2 on
                         new { compare1 = t1.i1, compare2 = t1.i2 } equals
                         new { compare1 = t2.i3, compare2 = t2.i4 }
                         select t1;
        }
        catch(Exception ex)
        {
            MessageBox.Show(ex.ToString());
        }
    }

示例2)它不起作用比较代码。结果为空。

public class tempClass1
    {
        public int i1;
        public int i2;
    }

    public class tempClass2
    {
        public int i3;
        public int i4;
    }

    public class CompareClass
    {
        public int compare1;
        public int compare2;
    }

    List<tempClass1> tempList1 = new List<tempClass1>();
    List<tempClass2> tempList2 = new List<tempClass2>();


    public MainWindow()
    {
        InitializeComponent();            

        try
        {
            tempList1.Add(new tempClass1() { i1 = 1, i2 = 2 });
            tempList1.Add(new tempClass1() { i1 = 3, i2 = 4 });
            tempList1.Add(new tempClass1() { i1 = 5, i2 = 6 });

            tempList2.Add(new tempClass2() { i3 = 1, i4 = 2 });

            var result = from t1 in tempList1
                         join t2 in tempList2 on
                         new CompareClass { compare1 = t1.i1, compare2 = t1.i2 } equals
                         new CompareClass { compare1 = t2.i3, compare2 = t2.i4 }
                         select t1;
        }
        catch(Exception ex)
        {
            MessageBox.Show(ex.ToString());
        }

我不知道这些代码有什么不同。请告诉我一些指导或反馈。

3 个答案:

答案 0 :(得分:0)

为什么第一个代码段有效?它在this文章的“Composite Key Join Example”段落中描述。 [编辑]正如其他人描述的两个动态对象的规则,比较踢在这里归结为基于属性的比较。

为什么第二个代码段不起作用?因为这种情况下的物体

new CompareClass { compare1 = t1.i1, compare2 = t1.i2 } equals
new CompareClass { compare1 = t2.i3, compare2 = t2.i4 }

没有在那里描述复合键,因此它们被视为普通对象并且也作为普通对象进行比较,即通过引用。由于它们是“即时”创建的,因此它们是eact迭代中的两个不同对象;因此,它们将始终不相等,并且这样的查询将始终返回空结果。

虽然有办法解决这个问题。不确定它对于这种特殊情况有什么意义,但从技术上讲它仍然是可能的。只需在CompareClass中实现IComparable,第二个代码片段也可以正常工作。

答案 1 :(得分:0)

在第一个示例中,您使用匿名类型进行比较。匿名类型的比较是在属性上进行的,而不是在实例上进行的。

https://msdn.microsoft.com/en-us/library/bb397696.aspx

  

因为匿名类型上的Equals和GetHashCode方法是   根据Equals和GetHashCode方法定义   属性,同一匿名类型的两个实例仅在相等时才相等   他们所有的财产都是平等的。

在第二个样本中,比较是在类的实例中进行的。

例如:

var c1 = new CompareClass { compare1 = 1, compare2 = 1 };
var c2 = new CompareClass { compare1 = 1, compare2 = 1 };
var c3 = c1;

var notEqual = c1 == c2; //false
var equal = c1 == c3; //true

对象c1的实例与对象c3相同。在c2中,值相同但实例不同。

答案 2 :(得分:0)

不同之处在于,在第一个代码中,您要比较匿名类型对象,在第二个 - CompareClass个实例中进行比较。

    var c1 = new CompareClass() { compare1 = tempList1[0].i1, compare2 = tempList1[0].i2 };
    var c2 = new CompareClass() { compare1 = tempList2[0].i3, compare2 = tempList2[0].i4 };

    var c3 = new { compare1 = tempList1[0].i1, compare2 = tempList1[0].i2 };
    var c4 = new { compare1 = tempList2[0].i3, compare2 = tempList2[0].i4 };

即使c1c2属性相同,但.GetHashCode()c1的{​​{1}}也不同,因为它是不同的实例。

c2

但匿名类型.GetHahCode()仅使用其属性。

  

因为匿名类型上的Equals和GetHashCode方法是根据属性的Equals和GetHashCode方法定义的,所以同一匿名类型的两个实例只有在它们的所有属性相等时才相等。

所以这会产生精确的哈希。

    c1.GetHashCode() == c2.GetHashCode()

如果要在LINQ语句中比较类实例,则需要使用自己的实现覆盖 c3.GetHashCode() == c4.GetHashCode() .GetHashCode()

.Equals()