I came across behavior in VB.NET today regarding boxing and link comparisons, which I did not expect. To illustrate, I wrote a simple program that tries to atomically update a variable of any type.
Here is a C # program ( 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);
The output of this program:
Hello World True True True False True True
This is as expected, and everything is working fine. Here is the same program in 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
Here's the conclusion:
Hello World True True True False True False
Here the last statement is false, which means the set is not working. Am I doing something wrong here or is there a problem in VB.NET?
(Note: Ignore volatile reads / write, this example has no threads, so it is not affected by the stream)
Edit: If I change T to an integer, then everything will work fine:
(Dotnetfiddle.net/X6uLZs). Also, if I change T to a user class, it also works fine:
dotnetfiddle.net/LnOOme