我在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());
}
我不知道这些代码有什么不同。请告诉我一些指导或反馈。
答案 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 };
即使c1
和c2
属性相同,但.GetHashCode()
和c1
的{{1}}也不同,因为它是不同的实例。
c2
但匿名类型.GetHahCode()
仅使用其属性。
因为匿名类型上的Equals和GetHashCode方法是根据属性的Equals和GetHashCode方法定义的,所以同一匿名类型的两个实例只有在它们的所有属性相等时才相等。
所以这会产生精确的哈希。
c1.GetHashCode() == c2.GetHashCode()
如果要在LINQ语句中比较类实例,则需要使用自己的实现覆盖 c3.GetHashCode() == c4.GetHashCode()
和.GetHashCode()
.Equals()