Creating an object with a null value through Activator.CreateInstance returns null

I am creating a system that turns a small script into a dll. I encounter a problem when I try to take a class with a null value and make it the default value for the parameter. The problem is that I need to create a user instance selected with a null value in the compiler and set it as a 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 by doing:

 object Test = Activator.CreateInstance(typeof(Nullable<int>)); Console.WriteLine(Test == null); 

returns true. This ONLY happens with Nullables. The structure created in C #, even the general one, is created perfectly. If I copy and paste the NULL value from the DotNetReflector (and remove the TypeDependencyAttribute, TargetPatchingOptOutAttribute and ThrowHelper calls since I don't have access to them), it shows False above.

What's happening? Is there any other possible way to create a NULL value if I don't know the general parameters before runtime?

+7
source share
2 answers

The problem is ParameterBuilder.SetConstant , not Activator.CreateInstance . SetConstant is a function for determining the default value for an optional parameter and requires that the specific value be provided as a constant. For ref classes, null is a valid specific value, but for value classes, before creating Nullable<> , null not a valid value. How do you, for example, unpack null in int ? So, SetConstant checked the value types to see if the particular value was passed as a null constant and throws an ArgumentException as a more descriptive error than the NullReferenceException you would get when unpacking null into a value class.

In the case of Nullable<> , null now a valid concrete value for the class of values. Nullable<> is itself a class of values, as shown in Activator.CreateInstance , and unboxing null to a Nullable<int> value makes sense. Here SetConstant has an error: it does not take this into account and throws a โ€œdescriptiveโ€ error, which is not really an error. Instead of fixing it from Microsoft, any SetConstant call with a null Nullable<> will have to implement the behavior protected by the wrong conditional. This means that you can delve into the private methods and fields of ParameterBuilder using reflection. Here is the code I made to handle this particular case. The standard SetConstant function should be used in situations that do not reflect an error.

 //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 reported a bug to Microsoft. They replied that it would not be fixed in .NET 3.5, but it was added to the internal error database.

UPDATE:

Bug fixed in .NET 4.0. ParameterBuilder.SetConstant now has a branch to the constant == null condition, which checks whether the value type is generalized, obtained from Nullable<> , and throws an exception only if it is not.

+1
source

From this MSDN blog :

Activator.CreateInstance can never expect to return null until; with this DCR, it will return null when an instance of type Nullable is created, but does not provide a non-zero T. For example, Activator.CreateInstance (typeof (Int32?)) returns null.

The problem is how Nullable<T> variables are put into the box, as explained in the blog post.

+6
source

All Articles