簡體   English   中英

為什么此多linq連接代碼不起作用?

[英]Why this multi linq join code does not work?

我在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());
        }

我不知道這些代碼有什么不同。 請告訴我一些指導方針或反饋。

為什么第一個片段有效? 本文的“復合鍵聯接示例”段落中對此進行了描述 [編輯]正如其他人描述的那樣,兩個動態對象比較的規則在這里踢進來,歸結為基於屬性的比較。

為什么第二個片段不起作用? 因為物體處於這種狀態

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

不會在此處進行描述,因此它們被視為普通對象,並且也被當作普通對象進行比較,即通過引用進行比較。 相比之下,由於它們是“即時”創建的,因此它們是eact迭代中的兩個不同的對象。 因此,它們將始終彼此不相等,並且這樣的查詢將始終返回空結果。

不過,有一種解決方法。 不確定對於這種特殊情況是否有意義,但從技術上講還是有可能的。 只需在CompareClass中實現IComparable,第二個代碼段也將正常工作。

在第一個示例中,您使用匿名類型進行比較。 匿名類型的比較是基於屬性而不是實例。

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中,值相同,但實例不同。

區別在於,在第一個代碼中,您正在比較匿名類型對象,在第二個代碼中,您正在比較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屬性相等,但是c1c2 .GetHashCode()也有所不同,因為它是不同的實例。

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

但是匿名類型.GetHahCode()僅使用其屬性。

因為匿名類型的Equals和GetHashCode方法是根據屬性的Equals和GetHashCode方法定義的,所以只有所有匿名屬性都相等時,相同匿名類型的兩個實例才相等。

因此,這將生成精確的哈希。

    c3.GetHashCode() == c4.GetHashCode()

如果要在LINQ語句中比較類實例,則需要使用自己的實現重寫.GetHashCode().Equals()

    public override bool Equals(object obj)
    {
        if (obj.GetType() != typeof(CompareClass))
            return false;

        if (this.compare1 == ((CompareClass)obj).compare1 && this.compare2 == ((CompareClass)obj).compare2)
            return true ;
        else
            return false;
    }

    // oversimplified, this link is more appropriate
    // http://stackoverflow.com/questions/263400/what-is-the-best-algorithm-for-an-overridden-system-object-gethashcode
    public override int GetHashCode()
    {
        return (this.compare1.GetHashCode() + this.compare2.GetHashCode()) * 11 + 2;
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM