2

I encountered an issue with an utility class that is used to check method parameters. It uses the dynamic keyword as generic type parameter a lot. There is a System.NullReferenceException thrown, that I don't understand. The exception has the following stacktrace:

(I apologize for the rather long excerpt, but it seems necessary to me...)

Microsoft.CSharp.dll!Microsoft.CSharp.RuntimeBinder.ExpressionTreeCallRewriter.GenerateLambda(Microsoft.CSharp.RuntimeBinder.Semantics.EXPRCALL)    Unknown
Microsoft.CSharp.dll!Microsoft.CSharp.RuntimeBinder.ExpressionTreeCallRewriter.VisitCALL(Microsoft.CSharp.RuntimeBinder.Semantics.EXPRCALL) Unknown
Microsoft.CSharp.dll!Microsoft.CSharp.RuntimeBinder.Semantics.ExprVisitorBase.Dispatch(Microsoft.CSharp.RuntimeBinder.Semantics.EXPR)   Unknown
Microsoft.CSharp.dll!Microsoft.CSharp.RuntimeBinder.Semantics.ExprVisitorBase.Visit(Microsoft.CSharp.RuntimeBinder.Semantics.EXPR)  Unknown
Microsoft.CSharp.dll!Microsoft.CSharp.RuntimeBinder.ExpressionTreeCallRewriter.Rewrite(Microsoft.CSharp.RuntimeBinder.Semantics.TypeManager, Microsoft.CSharp.RuntimeBinder.Semantics.EXPR, System.Collections.Generic.IEnumerable<System.Linq.Expressions.Expression>) Unknown
Microsoft.CSharp.dll!Microsoft.CSharp.RuntimeBinder.RuntimeBinder.CreateExpressionTreeFromResult(System.Collections.Generic.IEnumerable<System.Linq.Expressions.Expression>, Microsoft.CSharp.RuntimeBinder.RuntimeBinder.ArgumentObject[], Microsoft.CSharp.RuntimeBinder.Semantics.Scope, Microsoft.CSharp.RuntimeBinder.Semantics.EXPR)  Unknown
Microsoft.CSharp.dll!Microsoft.CSharp.RuntimeBinder.RuntimeBinder.BindCore(System.Dynamic.DynamicMetaObjectBinder, System.Collections.Generic.IEnumerable<System.Linq.Expressions.Expression>, System.Dynamic.DynamicMetaObject[], out System.Dynamic.DynamicMetaObject)    Unknown
Microsoft.CSharp.dll!Microsoft.CSharp.RuntimeBinder.RuntimeBinder.Bind(System.Dynamic.DynamicMetaObjectBinder, System.Collections.Generic.IEnumerable<System.Linq.Expressions.Expression>, System.Dynamic.DynamicMetaObject[], out System.Dynamic.DynamicMetaObject)    Unknown
Microsoft.CSharp.dll!Microsoft.CSharp.RuntimeBinder.BinderHelper.Bind(System.Dynamic.DynamicMetaObjectBinder, Microsoft.CSharp.RuntimeBinder.RuntimeBinder, System.Collections.Generic.IEnumerable<System.Dynamic.DynamicMetaObject>, System.Collections.Generic.IEnumerable<Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo>, System.Dynamic.DynamicMetaObject)  Unknown
Microsoft.CSharp.dll!Microsoft.CSharp.RuntimeBinder.CSharpConvertBinder.FallbackConvert(System.Dynamic.DynamicMetaObject, System.Dynamic.DynamicMetaObject) Unknown
System.Dynamic.Runtime.dll!System.Dynamic.ConvertBinder.FallbackConvert(System.Dynamic.DynamicMetaObject)   Unknown
System.Dynamic.Runtime.dll!System.Dynamic.DynamicMetaObject.BindConvert(System.Dynamic.ConvertBinder)   Unknown
System.Dynamic.Runtime.dll!System.Dynamic.ConvertBinder.Bind(System.Dynamic.DynamicMetaObject, System.Dynamic.DynamicMetaObject[])  Unknown
System.Dynamic.Runtime.dll!System.Dynamic.DynamicMetaObjectBinder.Bind(object[], System.Collections.ObjectModel.ReadOnlyCollection<System.Linq.Expressions.ParameterExpression>, System.Linq.Expressions.LabelTarget)   Unknown
System.Dynamic.Runtime.dll!System.Runtime.CompilerServices.CallSiteBinder.BindCore<System.Func<System.Runtime.CompilerServices.CallSite, object, object>>(System.Runtime.CompilerServices.CallSite<System.Func<System.Runtime.CompilerServices.CallSite, object, object>>, object[])    Unknown
System.Dynamic.Runtime.dll!System.Runtime.CompilerServices.CallSiteOps.Bind<System.Func<System.Runtime.CompilerServices.CallSite, object, object>>(System.Runtime.CompilerServices.CallSiteBinder, System.Runtime.CompilerServices.CallSite<System.Func<System.Runtime.CompilerServices.CallSite, object, object>>, object[])   Unknown
[Native to Managed Transition]  
[Managed to Native Transition]  
System.Linq.Expressions.dll!System.Linq.Expressions.Interpreter.MethodInfoCallInstruction.InvokeWorker(object[])    Unknown
System.Linq.Expressions.dll!System.Linq.Expressions.Interpreter.MethodInfoCallInstruction.Invoke(object[])  Unknown
System.Linq.Expressions.dll!System.Linq.Expressions.Interpreter.MethodInfoCallInstruction.Run(System.Linq.Expressions.Interpreter.InterpretedFrame) Unknown
System.Linq.Expressions.dll!System.Linq.Expressions.Interpreter.Interpreter.Run(System.Linq.Expressions.Interpreter.InterpretedFrame)   Unknown
System.Linq.Expressions.dll!System.Linq.Expressions.Interpreter.LightLambda.Run(object[])   Unknown
System.Linq.Expressions.dll!System.Linq.Expressions.Interpreter.CallInstruction.InterpretLambdaInvoke(System.Linq.Expressions.Interpreter.LightLambda, object[])    Unknown
System.Linq.Expressions.dll!System.Linq.Expressions.Interpreter.MethodInfoCallInstruction.InvokeWorker(object[])    Unknown
System.Linq.Expressions.dll!System.Linq.Expressions.Interpreter.MethodInfoCallInstruction.Invoke(object[])  Unknown
System.Linq.Expressions.dll!System.Linq.Expressions.Interpreter.MethodInfoCallInstruction.Run(System.Linq.Expressions.Interpreter.InterpretedFrame) Unknown
System.Linq.Expressions.dll!System.Linq.Expressions.Interpreter.Interpreter.Run(System.Linq.Expressions.Interpreter.InterpretedFrame)   Unknown
System.Linq.Expressions.dll!System.Linq.Expressions.Interpreter.LightLambda.Run(object[])   Unknown
[Lightweight Function]  
ProblematicUsageOfGenericsAndDynamic.exe!ProblematicUsageOfGenericsAndDynamic.ProblemClassA.Trouble<object>(System.Linq.Expressions.Expression<System.Func<object>>, out object)    C#
ProblematicUsageOfGenericsAndDynamic.exe!ProblematicUsageOfGenericsAndDynamic.ProblemClassB.Test(string, object)    C#
ProblematicUsageOfGenericsAndDynamic.exe!ProblematicUsageOfGenericsAndDynamic.MainPage.MainPage()   C#
ProblematicUsageOfGenericsAndDynamic.exe!ProblematicUsageOfGenericsAndDynamic.ProblematicUsageOfGenericsAndDynamic_XamlTypeInfo.XamlTypeInfoProvider.Activate_0_MainPage()  C#
ProblematicUsageOfGenericsAndDynamic.exe!ProblematicUsageOfGenericsAndDynamic.ProblematicUsageOfGenericsAndDynamic_XamlTypeInfo.XamlUserType.ActivateInstance() C#
[Native to Managed Transition]  
[Managed to Native Transition]  
ProblematicUsageOfGenericsAndDynamic.exe!ProblematicUsageOfGenericsAndDynamic.App.OnLaunched(Windows.ApplicationModel.Activation.LaunchActivatedEventArgs)  C#

Visual Studio Exception assistent showing the NullReferenceException

I simplified the code so that you can see and test for yourself:

ProblemClassA.cs:

using System.Linq.Expressions;

public class ProblemClassA
{
    private dynamic GetValue<T>(Expression<Func<T>> argument)
    {
        var getterLambda = Expression.Lambda<Func<dynamic>>(argument.Body);
        var getter = getterLambda.Compile();
        return getter();
    }

    public void Trouble<T>(Expression<Func<T>> argument, out T argumentValue)
    {
        argumentValue = this.GetValue(argument);
    }

    public void JustFine(Expression<Func<object>> argument, out object argumentValue)
    {
        argumentValue = this.GetValue(argument);
    }
}

ProblemClassB.cs:

public class ProblemClassB
{
    public void Test(string aString, object anObject)
    {
        ProblemClassA problemClassA = new ProblemClassA();

        object valueString;
        object valueObject;

        problemClassA.JustFine(() => aString, out valueString); // Works fine
        problemClassA.JustFine(() => anObject, out valueObject); // Works fine

        problemClassA.Trouble(() => aString, out valueString); // Works fine as well
        problemClassA.Trouble(() => anObject, out valueObject); // Throws an exception NullReferenceException
    }
}

How to test:

Test it by calling Test on an instance of ProblemClassA, e.g.:

new ProblemClassA().Test("This is a test", new object());

Can anybody please explain to me why the exception is thrown?

Thanks in advance!

Community
  • 1
  • 1
markus
  • 177
  • 1
  • 13
  • Not entirely sure _why_ it's thrown. Seems it's happening when it's trying to convert the `dynamic` return value from `GetValue` to the generic type `T` (which in the failing case, is `object`) If you change the line to: `argumentValue = (T)(object)this.GetValue(argument);` the error is resolved. (rather than converting `dynamic` to `T`, it converts to `object` _first_, then to `T`) This may or may not be a good thing. Why the use of `dynamic` here in the first place? Changing the expression to be `Expression.Lambda>(argument.Body);` still works for the examples you posted here. – Chris Sinclair Aug 05 '15 at 15:28
  • 1
    Something is funky here. I don't think this has anything to do with your use of expressions. Consider this simple case: `void Test(T value) { dynamic dynamicValue = value; T typedValue = (T)dynamicValue; }` These pass: `Test("asdf"); Test(null);` This fails with the same exception you have: `Test(new Object());` EDIT: Also, calling `Test("asdf");` and `Test(1.0);` passes as well, so it seems to only occur when `T` is `object`, and `value` is a non-null instance of `Object` proper. – Chris Sinclair Aug 05 '15 at 15:43
  • 2
    I found the [same issue reported](http://stackoverflow.com/questions/9931624/why-is-casting-a-dynamic-of-type-object-to-object-throwing-a-null-reference-exce), and apparently it was communicated up the chain. Appears to be a bug in the underlying runtime binding layer. Best I can suggest you do is the double cast of `argumentValue = (T)(object)this.GetValue(argument)`; I doubt there's a fix for it otherwise. Hopefully this is a viable solution. – Chris Sinclair Aug 05 '15 at 16:26
  • If this screws up the casting (because you want the dynamic check for explicit conversions) maybe do an explicit `typeof(T) == typeof(object)` check; if `T` is `object`, do the special `(T)(object)` cast, otherwise default to the standard cast. – Chris Sinclair Aug 05 '15 at 16:30
  • Thanks for the deep analysis, @ChrisSinclair! I think I will just stick with avoiding to use the `dynamic` keyword and use `object` instead... – markus Aug 06 '15 at 09:16

0 Answers0