Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does a dynamic parameter in a generic method throw a null reference exception when using an Object? [duplicate]

I wonder if someone could explain why in this code

public class SomeClass
{
    public T GenericMethod<T>(dynamic value)
    {
        return (T)value;
    }
}

the 'return value;' statement throws an null reference exception when called with:

new SomeClass().GenericMethod<object>(new object()); // throws System.NullReferenceException

It works as expected when called with:

new SomeClass().GenericMethod<string>("SomeString"); // returns SomeString
new SomeClass().GenericMethod<object>("SomeString"); // returns SomeString

Note: The following compiles and runs just fine

public class SomeOtherClass
{
    public T GenericMethod<T>(object value)
    {
        return (T)value;
    }
}

The stacktrace:

System.NullReferenceException: Object reference not set to an instance of an object.
   at Microsoft.CSharp.RuntimeBinder.ExpressionTreeCallRewriter.GenerateLambda(EXPRCALL pExpr)
   at Microsoft.CSharp.RuntimeBinder.Semantics.ExprVisitorBase.Visit(EXPR pExpr)
   at Microsoft.CSharp.RuntimeBinder.ExpressionTreeCallRewriter.Rewrite(TypeManager typeManager, EXPR pExpr, IEnumerable`1 listOfParameters)
   at Microsoft.CSharp.RuntimeBinder.RuntimeBinder.BindCore(DynamicMetaObjectBinder payload, IEnumerable`1 parameters, DynamicMetaObject[] args, DynamicMetaObject& deferredBinding)
   at Microsoft.CSharp.RuntimeBinder.RuntimeBinder.Bind(DynamicMetaObjectBinder payload, IEnumerable`1 parameters, DynamicMetaObject[] args, DynamicMetaObject& deferredBinding)
   at Microsoft.CSharp.RuntimeBinder.BinderHelper.Bind(DynamicMetaObjectBinder action, RuntimeBinder binder, IEnumerable`1 args, IEnumerable`1 arginfos, DynamicMetaObject onBindingError)
   at Microsoft.CSharp.RuntimeBinder.CSharpConvertBinder.FallbackConvert(DynamicMetaObject target, DynamicMetaObject errorSuggestion)
   at System.Dynamic.DynamicMetaObject.BindConvert(ConvertBinder binder)
   at System.Dynamic.DynamicMetaObjectBinder.Bind(Object[] args, ReadOnlyCollection`1 parameters, LabelTarget returnLabel)
   at System.Runtime.CompilerServices.CallSiteBinder.BindCore[T](CallSite`1 site, Object[] args)
   at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0)
like image 633
pvill Avatar asked May 23 '16 13:05

pvill


People also ask

Why am I getting a null reference exception?

A NullReferenceException happens when you try to access a reference variable that isn't referencing any object. If a reference variable isn't referencing an object, then it'll be treated as null .

What is a null reference exception?

A NullReferenceException exception is thrown when you try to access a member on a type whose value is null . A NullReferenceException exception typically reflects developer error and is thrown in the following scenarios: You've forgotten to instantiate a reference type.

How do you avoid null reference exception?

Use Null Coalescing to Avoid NullReferenceExceptions It works with all nullable data types. The following code throws an exception without the null coalescing. Adding “?? new List<string>()” prevents the “Object reference not set to an instance of an object” exception.

How can you tell if a dynamic object is null?

In order to check a dynamic for null, you should cast it as an object. For example, dynamic post = SomeMethod(); if (post. modified == null){ //could return errors. }


2 Answers

It appears it's a bug first reported in 2012 but still apparently not fixed (as of May 24th 2016)

like image 161
mark_h Avatar answered Oct 07 '22 21:10

mark_h


Update

As the marked duplicate indicates this is a known bug in the .NET runtime.


The problem is likely a poor indication of an invalid run-time cast. If you take out the dynamic binding and make the parameter type object you get the compiler error

Cannot implicitly convert type 'object' to 'T'. An explicit conversion exists (are you missing a cast?)

Since by adding dynamic this casting is done at run-time, this implicit conversion error manifests itself differently at run-time with a vague NullReferenceException in the run-time bindings.

I'm not an expert in the inner workings of the DLR, but I suspect that an object passed as a dynamic value is not really a pure object at run-time. I suspect that it's some sort of wrapper around object, and thus can't be implicitly cast to object at run-time.

An explicit reference cast

return (T)(object)value;

will not generate that error.

like image 33
D Stanley Avatar answered Oct 07 '22 21:10

D Stanley