Linq,VB - 匿名类型无法转换为匿名类型

3

我是Linq的初学者,希望有人能指点我正确的方向。这里有什么问题?这些匿名类型似乎具有相同的签名。

          '*** Get all of the new list items'
          Dim dsNewFiles = From l1 In list1 _
                           Where Not (From l2 In list2 _
                                      Select l2.id, l2.timestamp).Contains(New With {l1.id, l1.timestamp})

我希望能够在上述代码中进行高亮显示,但是我收到了编译错误:

Value of type '<anonymous type> (line n)' cannot be converted to '<anonymous type> (line n)'.

在".Contains(New With{l1.id, l1.timestamp})"中,我认为它认为匿名类型在某些方面是不同的,但是id和timestamp列在两个列表中都是相同的。它们也按照相同的顺序排列。除此之外,还有什么可能不同呢?

[编辑 2009年7月10日16:28 EST]

我尝试了用户Meta-Knight提供的代码(New With {Key l1.id, l1.timestamp}),它修复了编译错误。然而,当我使用List1和List2运行代码时,如下所示:

List1                         List2
id     timestamp              id     timestamp
--     ----------             --     ----------
01     2009-07-10 00:00:00    01     2009-07-10 00:00:00

结果是:
dsNewFiles
id     timestamp
--     ----------
01     2009-07-10 00:00:00

它应该是一个空列表。
2个回答

1

当你生成匿名类型时,如果它们没有使用相同的名称并且按照完全相同的顺序指定其属性,则它们将作为单独的类型生成。因此,你的示例与我执行以下操作相同:

Class A 
BeginClass 
    Begin ID as Int Begin ... End 
    Stuff as String Begin ... End 
EndClass

Class B 
BeginClass 
    Begin Stuff as String Begin ... End 
    ID as Int Begin ... End 
EndClass

From a In someListofAs
Where Not (From b In someListofBs Select b).Contains(a)

顺便说一下,那是完全的空气代码。

另外,在你的示例中,LINQ 的一部分是匿名类型,而另一部分不是。这可能是你的问题所在。

试试这个:

From l1 In list1 _
Where Not (From l2 In list2 _
    Select New With { ID = l2.id, Timestamp = l2.timestamp}).Contains(
        New With { ID = l1.id, Timestamp = l1.timestamp})

啊,我明白了。你有什么想法来完成我想做的事吗? - Daniel
我看到你的编辑了...我不认为那会起作用,至少看起来不是这样。这不是和上面一样的情况吗?两个新的"Withs"都会创建具有不同签名的对象? - Daniel
@hypoxide 我觉得这两个签名看起来一样。除非我打错了什么,但我没有发现。你可以试一下,看看你得到什么结果。我手头没有VS,否则我会试试的。 - Joseph
@Joseph:没错,但是从我理解你对上面例子中为什么无法比较生成的匿名类型的解释来看,似乎同样适用于这些类型。尽管它们的签名看起来相同,但它们本质上有所不同,因此不能像比较相同类型一样进行比较?也许我需要在这里使用lambda函数作为比较方法?为了记录,我确实尝试过。虽然它可以正常运行,但并没有起作用。List1和List2包含相同的集合,但上述操作的结果却产生了所有List1的元素。 - Daniel

1

只需将您代码的最后一部分更改为:

New With {Key l1.id, Key l1.timestamp}

我测试了这段代码,它是有效的。

编辑:

我不知道为什么这对你不起作用,我会把整个代码都贴出来以确保无误。

Dim dsNewFiles = From l1 In list1 _
                           Where Not (From l2 In list2 _
                                      Select l2.ID, l2.TimeStamp).Contains(New With {Key l1.ID, Key l1.TimeStamp})

另一个选择是只需执行以下操作:

Dim dsNewFiles = list1.Except(list2)

为了使其正常工作,您的类必须覆盖Equals和GetHashCode,并实现IEquatable(Of T)接口。在MSDN(底部)有一个非常好的例子(链接)
如果ID和Timespan在您的类中不表示相等,则可以使用自定义的IEqualityComparer(Of T)作为第二个参数。

@Meta-Knight:感谢您的见解。编译错误已经消失了。然而,代码仍然不能像预期的那样工作。请参见上面的编辑。 - Daniel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接