Creating a nullable object via Activator.CreateInstance returns null

c#, reflection

Solution

The problem is in `ParameterBuilder.SetConstant`, not `Activator.CreateInstance`. `SetConstant` is a function for defining the default value of an optional parameter, and requires a concrete value be provided as the constant. For ref classes, `null` is a valid concrete value, but for value classes prior to the creation of `Nullable<>`, `null` was not a valid value. How do you unbox `null` into an `int`, for example? So `SetConstant` checked value types to see if the concrete value passed in as the constant was `null` and throws an `ArgumentException` as a more descriptive error than the `NullReferenceException` you'd get for unboxing a null into a value class.

In the case of a `Nullable<>`, `null` is now a valid concrete value for a value class. `Nullable<>` itself is a value class, as seen with `Activator.CreateInstance`, and unboxing `null` into a `Nullable<int>` has meaning. This is where `SetConstant` has a bug: it fails to take this into account and throws a 'descriptive' error for what isn't actually an error. In lieu of a bugfix from Microsoft, any call to `SetConstant` with a null `Nullable<>` will have to implement the behavior that's guarded by the incorrect conditional. This means digging into `ParameterBuilder`'s private methods and fields using reflection. Here's the code I made to handle just this case. The standard `SetConstant` function should be used in situations that don't manifest the bug.

//ModuleBuilder module : a parameter passed into the containing function, the module which is being built (which contains the method that has the optional parameter we are setting the constant for)
//ParameterBuilder optParam : A parameter passed into the containing function, the parameter that is being built which is to have the null default value.
MethodInfo method = typeof(TypeBuilder).GetMethods(BindingFlags.Static | BindingFlags.NonPublic)
    .Where(m => m.Name == "SetConstantValue" && m.GetParameters().Length > 0 && m.GetParameters()[0].ParameterType.Name == "RuntimeModule")
    .Single();
var RuntimeHandle = typeof(ModuleBuilder).GetMethod("GetNativeHandle", BindingFlags.NonPublic | BindingFlags.Instance);
method.Invoke(null, new object[]
{
    RuntimeHandle.Invoke(module, new object[]{}),
    optParam.GetToken().Token,
    0x12,
    null
});

I have reported the bug to Microsoft. They responded that it wouldn't be fixed in .NET 3.5, but it was added to the internal bug database.

UPDATE:

The bug has been fixed in .NET 4.0. `ParameterBuilder.SetConstant` now has a branch to the `constant == null` conditional that checks to see if a value type is a generic derived from `Nullable<>` and only throws the exception if it is not.

Problem

I'm creating a system that turns a small script into a dll. I'm encountering a problem when I try to take a nullable value class and make it the default value of a parameter. The problem is that I need to create an instance of user selected nullable within the compiler and set it as the constant. Unfortunately, whenever I use `Activator.CreateInstance(NullableType)` (where NullableType is a created type from user input) I get `null` as the return value. For example, simply executing: ``` object Test = Activator.CreateInstance(typeof(Nullable<int>)); Console.WriteLine(Test == null); ``` returns true. This ONLY happens with Nullables. A struct created in C#, even a generic one, is created fine. Heck, if I copy & paste nullable from DotNetReflector (and remove TypeDependencyAttribute, TargetPatchingOptOutAttribute, and ThrowHelper calls since I don't have access to those), it shows False above. What is going on? Is there any other possible way to create a nullable when I don't know the generic parameters until run-time?

Original source

Related problems