【问题标题】:IEnumerable.Min() returns strange results with generic objectsIEnumerable.Min() 使用通用对象返回奇怪的结果
【发布时间】:2019-06-20 19:54:26
【问题描述】:

如果我有一个对象列表(例如,List(Of Foo))并且我想获得列表元素中特定属性的最小值,我可以使用类似的东西:

listOfFoo.Min(Function(i) i.Id)

没问题。现在,如果列表恰好是空的,上面的代码将不起作用。所以,我使用类似的东西:

listOfFoo.DefaultIfEmpty().Min(Function(i) i?.Id).GetValueOrDefault()

这也很好直到列表变成通用对象列表然后它开始返回非常奇怪的结果。

重现问题的代码:

Class Foo
    Public Property Id As Integer
End Class

Class Bar
    Public Property Id As Integer
End Class

Function GetMin(list As List(Of Foo)) As Integer
    Return list.DefaultIfEmpty().Min(Function(i) i?.Id).GetValueOrDefault()
End Function

Function GetMin(Of T As Bar)(list As List(Of T)) As Integer
    Return list.DefaultIfEmpty().Min(Function(i) i?.Id).GetValueOrDefault()
End Function

Sub Main()
    Dim fooList As New List(Of Foo) From {New Foo() With {.Id = 2}, New Foo() With {.Id = 3}}
    Dim min = GetMin(fooList)
    Console.WriteLine(min)      ' 2 --> Great!

    Dim barList As New List(Of Bar) From {New Bar() With {.Id = 2}, New Bar() With {.Id = 3}}
    Dim min2 = GetMin(Of Bar)(barList)
    Console.WriteLine(min2)     ' 12 --> Huh?!!!!

    Console.ReadLine()
End Sub

正如 cmets 所示,第二个列表返回 12,即使它与第一个具有相同的值。此外,您会注意到返回的值不是随机的;它随着类的属性而变化。例如,如果我向Bar 添加另一个字符串属性,它会返回606600 而不是12

有人对此有解释吗?还是我做错了什么?


更新:我认为这可能是 VB.NET 中的一个错误,因为我刚刚尝试在 C# 中做同样的事情,它返回了正确的值。 Here's the C# code 如果有人想看看。我对两者都使用了 .NET 4.5.2,但我也使用 VB 在 .NET 4.6.1 上进行了测试,但它仍然无法正常工作。

更新 #2:

我正在使用 VS2015。当我切换到 VS2017(相同的 .NET 版本)时,问题似乎消失了。

【问题讨论】:

  • 我使用 linqpad 运行了您的代码,它为两者返回值 2。您是否粘贴了可以运行和比较的完整代码?
  • @shahkalpesh 我正在使用 VS。让我试试 LinqPad 看看.. 编辑:是的,您几乎可以按原样复制和粘贴代码。
  • @shahkalpesh 我尝试使用 LinqPad,但它甚至无法编译(看起来 LinqPad 无法识别空条件运算符语法)。我尝试使用免费版 v4.59。
  • 这是我使用的fiddle。不过,我不得不做出一些改变。它打印 2 两次。
  • 将 VS 2015 生成的 IL 与 VS 2017 生成的 IL 进行比较(或者甚至在 ILSpy 中反编译并检查差异)可能会很有趣。我猜一个编译器错误要么使它调用错误的东西(例如 GetHashCode 而不是 get_Id),要么将 Id 的检索指向内存中的错误位置。

标签: .net vb.net generics visual-studio-2015


【解决方案1】:

正如我在问题更新中提到的,这似乎可以在特定版本的 Visual Studio 上生产(在 VS2015 上生产,但不是在 2017 年生产)所以我认为这是 VB 编译器中的一个错误在VS2015中使用。

很遗憾,我目前无法将此项目升级到 VS2017,因此作为一种解决方法,我将替换此行:

min = listOfFoo.DefaultIfEmpty().Min(Function(i) i?.Id).GetValueOrDefault()

与:

min = If(listOfFoo.Count = 0), 0, listOfFoo.Min(Function(i) i.id)

..虽然在可读性方面我更喜欢前者。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-08-08
    • 2012-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多