简体   繁体   中英

Is it possible to cheat C# compiler to box Nullable<T> struct ant not its value?

Well, the question may seem odd. And it really is.
Yet I strongly believe that such hacks help in understanding the language and .net platform.

It is how C# compiler treats nullable types implies this question.

Nullable<T> is a struct. But compiler boxes not this struct but the value it holds or just null reference.

It is also intersting how unboxing will work in the case of the boxed Nullable.

Nullable<int> myInt = boxedStruct as Nullable<int>;

here I meen that boxedStruct is not a boxed int but the whole struct.

Well, may be Nullables are treated differently at CLR level because I cannot understand the ouptut of the program below.

class Program
{
    public static bool? Property { get; set; }

    static void Main(string[] args)
    {
        Property = true;

        var valueType = typeof (Program).GetProperty("Property").GetValue(null).GetType();
        var propType = typeof (Program).GetProperty("Property").PropertyType;

        Console.WriteLine("Value's type '{0}' is the same as type of the property '{1}' - '{2}'", valueType, propType, valueType == propType);
        Console.ReadKey();
    }
}

The output:

Value's type 'System.Boolean' is the same as type of the property 'System.Nullable`1[System.Boolean]' - 'False'

Update:

Here what specification (ECMA 335) says:

I.8.2.4 Boxing and unboxing of values
...
If the value type is a nullable type—defined as an instantiation of the value type System.Nullable—the result is a null reference or bitwise copy of its Value property of type T, depending on its HasValue property (false and true, respectively).

So if I understand this correctly. Nullable<T> strcut cannot be boxed in .Net Framework and it's not just impossible with C# compiler but with CLR as well.

I am conjecturing that the question you are trying to ask is:

Can you box a Nullable<int> value without producing a null reference or a boxed int value, but instead an actually boxed Nullable<int> ?

No.

Is it possible to cheat C# compiler to box Nullable<T> ?

No, as it is not the compiler who does the boxing, it is the CLR. Yes, the boxing of nullable types is specifically handled in the CLR itself.

So is there a way to box a nullable struct without this special handling? Also no.

But it is possible to box another structure that looks like Nullable<T> (ensuring it has the appropriate layout) and with the help of undocumented keywords and memory hacking trick the CLR into thinking the boxed object is actually of Nullable<T> .
Beware! This code should be used only for educational purposes. I can't guarantee it will work on other platforms or work at all in different conditions, because it relies on the underlying layout of managed objects.

public static unsafe object BoxNullable<T>(T? nullable) where T : struct
{
    object scam = new NullableFake<T>(nullable);
    TypedReference tr = __makeref(scam);
    IntPtr typehandle = typeof(Nullable<T>).TypeHandle.Value;
    IntPtr* trstruct = (IntPtr*)&tr;
    **((IntPtr**)trstruct[0]) = typehandle;
    return scam;
}

struct NullableFake<T> where T : struct
{
    public readonly T? Value;

    public NullableContainer(T? nullable)
    {
        Value = nullable;
    }
}

The NullableFake<T> structure has the same layout as Nullable<T> , so it is safe to use it for boxing. TypedReference is used for obtaining a pointer to the variable (that contains a pointer to the object), exposing the object itself. The first value in the object's memory layout is a pointer to the object's type. Overwriting it results in the CLR thinking the type is different.

I don't know any safer way to do it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM