今天我在VB.NET中遇到了一个关于装箱和引用比较的行为,这让我感到意外。为了说明问题,我编写了一个简单的程序,尝试以原子方式更新任何类型的变量。
以下是C#程序(https://dotnetfiddle.net/VsMBrg):
这个程序的输出是:
这是预期的,一切似乎都正常工作。 以下是同样的程序的VB.NET版本(https://dotnetfiddle.net/lasxT2):
这里的最后一句话是错误的,这意味着该集合未起作用。 我做错了什么还是问题出在VB.NET上?
(注:忽略“Volatile reads / writes”,此示例没有线程,因此不受线程影响)
以下是C#程序(https://dotnetfiddle.net/VsMBrg):
using System;
public static class Program
{
private static object o3;
public static void Main()
{
Console.WriteLine("Hello World");
Test<DateTimeOffset?> value = new Test<DateTimeOffset?>();
Console.WriteLine(value.Value == null);
DateTimeOffset dt1 = new DateTimeOffset(2017, 1, 1, 1, 1, 1, TimeSpan.Zero);
DateTimeOffset dt2 = new DateTimeOffset(2017, 1, 2, 1, 1, 1, TimeSpan.Zero);
Console.WriteLine(value.TrySetValue(null, dt1));
Console.WriteLine(value.Value == dt1);
// this should fail
Console.WriteLine(value.TrySetValue(null, dt2));
Console.WriteLine(value.Value == dt1);
// this should succeed
Console.WriteLine(value.TrySetValue(dt1, dt2));
}
}
public class Test<T>
{
public T Value {
get { return (T)System.Threading.Volatile.Read(ref _value); }
}
private object _value;
public bool TrySetValue(T oldValue, T newValue)
{
object curValObj = System.Threading.Volatile.Read(ref _value);
if (!object.Equals((T)curValObj, oldValue))
return false;
object newValObj = (object)newValue;
return object.ReferenceEquals(System.Threading.Interlocked.CompareExchange(ref _value, newValObj, curValObj), curValObj);
}
}
这个程序的输出是:
Hello World
True
True
True
False
True
True
这是预期的,一切似乎都正常工作。 以下是同样的程序的VB.NET版本(https://dotnetfiddle.net/lasxT2):
Imports System
Public Module Module1
private o3 as object
Public Sub Main()
Console.WriteLine("Hello World")
Dim value As New Test(Of DateTimeOffset?)
Console.WriteLine(value.Value is nothing)
Dim dt1 As New DateTimeOffset(2017, 1, 1, 1, 1, 1, TimeSpan.Zero)
Dim dt2 As New DateTimeOffset(2017, 1, 2, 1, 1, 1, TimeSpan.Zero)
Console.WriteLine(value.TrySetValue(Nothing, dt1))
Console.WriteLine(value.Value = dt1)
' This should fail
Console.WriteLine(value.TrySetValue(Nothing, dt2))
Console.WriteLine(value.Value = dt1)
' This should succeed
Console.WriteLine(value.TrySetValue(dt1, dt2))
End Sub
End Module
public class Test(Of T)
Public readonly Property Value As T
Get
Return CType(Threading.Volatile.Read(_value), T)
End Get
End Property
Private _value As Object
Public Function TrySetValue(oldValue As T, newValue As T) As Boolean
Dim curValObj As Object = Threading.Volatile.Read(_value)
If Not Object.Equals(CType(curValObj, T), oldValue) Then Return False
Dim newValObj = CObj(newValue)
Return Object.ReferenceEquals(Threading.Interlocked.CompareExchange(_value, newValObj, curValObj), curValObj)
End Function
end class
这里的输出是:
Hello World
True
True
True
False
True
False
这里的最后一句话是错误的,这意味着该集合未起作用。 我做错了什么还是问题出在VB.NET上?
(注:忽略“Volatile reads / writes”,此示例没有线程,因此不受线程影响)
编辑:
如果我将T更改为整数,那么一切都可以正常工作:
(dotnetfiddle.net/X6uLZs)。
此外,如果我将T更改为自定义类,则也可以正常工作:
dotnetfiddle.net/LnOOme