[英]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 };
即使c1
和c2
屬性相等,但是c1
和c2
.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.