相同的(?)C#和VB.NET LINQ查询返回不同的结果
可能真的很容易,但我看不到它……
我在LINQ中复制MS Access查询。 我先用C#编写它来测试它,因为我更喜欢C#,然后我把它翻译成VB.Net语法。 据我所知,两个查询应该是相同的,但是当C#查询返回正确的结果时,VB.NET会返回零结果。
谁能看出差异可能在哪里?
C#查询:
var table1 = dc.MainTable.Where(o => o.Year == 423).ToList().Select(o => new { Key_ID = o.Key_ID.Value, CropID = o.CropID.Value, GroupID = o.GroupID.Value, Surface1 = o.Surface1.Value, Surface2 = o.Surface2.Value }); var table2 = dc.OtherTable.Where(o => o.Year == 423).ToList().Select(o => new { Key_ID = o.Key_ID.Value, CropID = int.Parse(o.SAKU_CD), GroupID = int.Parse(o.SAN_DAN_NO), Surface1 = Convert.ToDouble(o.KEIHAN_MEN.Value), Surface2 = Convert.ToDouble(o.SAKU_MEN.Value) }); var output = table1.Join(table2, t1 => new { t1.Key_ID, t1.CropID, t1.GroupID, t1.Surface1, t1.Surface2 }, t2 => new { t2.Key_ID, t2.CropID, t2.GroupID, t2.Surface1, t2.Surface2 }, (t1, t2) => new OutputDataType() { Key_ID = t1.Key_ID, Year = 423 }).ToList();
VB.NET查询:
Dim table1 = MainTable.Where(Function(o) o.Year.Value = 423).ToList().Select(Function(o) New With { .Key_ID = o.Key_ID.Value, .CropID = o.CropID.Value, .GroupID = o.GroupID.Value, .Surface1 = o.Surface1.Value, .Surface2 = o.Surface2.Value }).ToList() Dim table2 = OtherTable.Where(Function(o) o.Year.Value = 423).ToList().Select(Function(o) New With { .Key_ID = o.Key_ID.Value, .CropID = Convert.ToInt32(o.SAKU_CD), .GroupID = Convert.ToInt32(o.SAN_DAN_NO), .Surface1 = Convert.ToDouble(o.KEIHAN_MEN.Value), .Surface2 = Convert.ToDouble(o.SAKU_MEN.Value) }).ToList() Dim output = table1.Join(table2, Function(t1) New With { t1.Key_ID, t1.CropID, t1.GroupID, t1.Surface1, t1.Surface2 }, Function(t2) New With { t2.Key_ID, t2.CropID, t2.GroupID, t2.Surface1, t2.Surface2 }, Function(t1, t2) New OutputDataType With {.Key_ID = t1.Key_ID, .Year = 423}).ToList()
在C#和VB.Net中, table1
和table2
是相同的,所以它必须是失败的Join
。
编辑
我刚刚将VB.Net中的Join
更改为查询语法,如下所示:
Dim output = From t1 In MainTable Join t2 In OtherTable On t1.Key_ID Equals t2.Key_ID And t1.GroupID Equals t2.GroupID And t1.CropID Equals t2.CropID And t1.Surface1 Equals t2.Surface1 And t1.Surface2 Equals t2.Surface2 Select New OutputDataTypeData With {.Key_ID = t1.Key_ID, .Year = 423}
这给出了正确的结果。 但我真的不明白这与扩展方法Join
语法有何不同?
使用Join
扩展方法时,使用Equals
方法比较作为outerKeySelector
和innerKeySelector
参数提供的键。
但是C#和VB.Net在这里处理匿名类型的方式不同:
C#
var a = new {Foo = 1, Bar = 2 }; var b = new {Foo = 1, Bar = 2 }; bool result = a.Equals(b); // true
VB.Net
Dim a = new with {.Foo = 1, .Bar = 2} Dim b = new with {.Foo = 1, .Bar = 2} Dim result = a.Equals(b) ' False '
这里发生了什么事?
C#使用值相等来比较两个对象,比较属性的值。
VB.Net使用引用相等来比较两个对象,因此结果为False
。
要使代码有效,您必须明确告诉VB.Net使用Key
关键字比较属性:
关键属性在几个基本方面与非关键属性不同:
- 仅比较关键属性的值以确定两个实例是否相等。
- 键属性的值是只读的,不能更改。
- 对于匿名类型,只有关键属性值包含在编译器生成的哈希码算法中。
Dim a = new with {Key .Foo = 1, Key .Bar = 2} Dim b = new with {Key .Foo = 1, Key .Bar = 2} Dim result = a.Equals(b) # True
查询语法有效,因为在这种情况下,您不是比较匿名类型/对象,而只是比较int
和double
。