9

可能真的很容易,但我就是看不到它......

我在 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.Nettable1table2都是一样的,所以它一定是Join失败的。

编辑

我只是将JoinVB.Net 中的更改为查询语法,如下所示:

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语法有何不同?

4

1 回答 1

12

当您使用Join扩展方法时,您提供的键outerKeySelectorinnerKeySelector参数将使用该Equals方法进行比较。

但是 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

查询语法有效,因为在这种情况下,您不是在比较匿名类型/对象,而只是比较ints 和doubles。

于 2013-02-18T08:12:40.870 回答