Difference in object boxing / comparing references between C# and VB.Net

I encountered a behavior in VB.NET today regarding boxing and reference comparison that I did not expect. To illustrate I wrote a simple program which tries to atomically update a variable of any type.

Here is a program in 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);


The output of this program is:

Hello World

This is as expected and everything seems to work 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
            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 the output is:

Hello World

Here the last statement is false which means that the set did not work.
Am I doing something wrong here or is the problem in the VB.NET?

(Note: Ignore the Volatile reads/writes, this example has no threads so it is not affected by threading)

If I change the T to integer then everything works OK:
Also if I change T to a custom class it also works OK:

Difference in object boxing / comparing references between C# and VB.Net