列表(Of T)由未知英雄保存?

Bjø*_*sjå 5 .net vb.net

List(Of T)当我将内部_version字段设置为Integer.MaxValue并添加新项时,是什么阻止了抛出算术溢出异常?


TL; DR:

正如您在查看源代码时所看到的那样,没有针对潜在算术溢出的保护.但是,Integer.MinValue如果值是最大值,那么某些事物就会将值设置为.

<__DynamicallyInvokable()> _
Public Sub Add(ByVal item As T)
    If (Me._size = Me._items.Length) Then
        Me.EnsureCapacity((Me._size + 1))
    End If
    Me._items(Me._size++) = item
    Me._version += 1
End Sub
Run Code Online (Sandbox Code Playgroud)

详细

由于List(Of T)的内部项数组是私有的,我不会使用反射来访问它,我决定使用原始List(Of T)源代码创建自定义列表.

但是,我注意到,如果版本达到Integer.MaxValue,则无法防止潜在的算术溢出.

Me._version += 1
Run Code Online (Sandbox Code Playgroud)

所以我修改了代码:

Me._version = If((Me._version = Integer.MaxValue), Integer.MinValue, (Me._version + 1I))
Run Code Online (Sandbox Code Playgroud)

现在开始有趣的部分; 出于好奇,我设置了一个测试,我使用反射将内部_version字段设置为最大值.

Dim flags As BindingFlags = (BindingFlags.Instance Or BindingFlags.NonPublic)
Dim list As New List(Of String)
Dim _version As FieldInfo = GetType(List(Of String)).GetField("_version", flags)

_version.SetValue(list, Integer.MaxValue)
Debug.WriteLine("Count: {0}, Version: {1}", list.Count, _version.GetValue(list))
list.Add("str")
Debug.WriteLine("Count: {0}, Version: {1}", list.Count, _version.GetValue(list))
Run Code Online (Sandbox Code Playgroud)

我对结果感到震惊:

数:0,版本:2147483647
计数:1,版本:-2147483648

如果达到最大值,源代码中没有任何内容将字段设置为最小值.我甚至查看了DynamicallyInvokable属性,但据我所知,它不相关.

<__DynamicallyInvokable()> _
Public Sub Add(ByVal item As T)
    If (Me._size = Me._items.Length) Then
        Me.EnsureCapacity((Me._size + 1))
    End If
    Me._items(Me._size++) = item
    Me._version += 1
End Sub

Private Sub EnsureCapacity(ByVal min As Integer)
    If (Me._items.Length < min) Then
        Dim num As Integer = IIf((Me._items.Length = 0), 4, (Me._items.Length * 2))
        If (num > &H7FEFFFFF) Then
            num = &H7FEFFFFF
        End If
        If (num < min) Then
            num = min
        End If
        Me.Capacity = num
    End If
End Sub

<__DynamicallyInvokable()> _
Public Property Capacity As Integer
    <TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries"), __DynamicallyInvokable()> _
    Get
        Return Me._items.Length
    End Get
    <__DynamicallyInvokable()> _
    Set(ByVal value As Integer)
        If (value < Me._size) Then
            ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.value, ExceptionResource.ArgumentOutOfRange_SmallCapacity)
        End If
        If (value <> Me._items.Length) Then
            If (value > 0) Then
                Dim destinationArray As T() = New T(value - 1) {}
                If (Me._size > 0) Then
                    Array.Copy(Me._items, 0, destinationArray, 0, Me._size)
                End If
                Me._items = destinationArray
            Else
                Me._items = List(Of T)._emptyArray
            End If
        End If
    End Set
End Property
Run Code Online (Sandbox Code Playgroud)

Hei*_*nzi 10

基类库是用C#编写的,而不是用VB.NET编写的.

默认情况下,C#中的算术运算不会抛出溢出异常.相反,正如你所注意到的那样,他们默默地将价值包裹起来.

这个决定可能是出于效率的原因; 不是每个人都同意.可以在以下问题中找到更多信息: