Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Possible bug in C# dynamic? [duplicate]

Tags:

c#

dynamic

I have encountered issues with using dynamic variables in C#. This arose while coding NancyFx routing modules, but I have boiled down the issue to the example below. While I received a different exception in the original code, the example code still throws an exception that I believe is erroneous. Does anyone see what is going on here, or have others encountered similar problems?

Note that the following posts may be related: StackOverflowException when accessing member of generic type via dynamic: .NET/C# framework bug? System.Dynamic bug?

The code:

class Program
{
    static void Main(string[] args)
    {
        var dictionary = new Dictionary<string, object>();
        dictionary.Add("number", 12);
        var result = MethodUsesExplicitDeclaration(dictionary);
        var result2 = MethodUsesImplicitDeclaration(dictionary);
    }

    static dynamic MethodUsesExplicitDeclaration(dynamic reallyDictionary)
    {
        // this works, ostensibly because the local variable is explicitly declared
        IDictionary<string, object> dictionary = CastDictionary(reallyDictionary);
        return dictionary.Get<int>("number");
    }

    static dynamic MethodUsesImplicitDeclaration(dynamic reallyDictionary)
    {
        // this throws an exception, and the only difference is 
        // that the variable declaration is implicit
        var dictionary = CastDictionary(reallyDictionary);
        return dictionary.Get<int>("number");
    }

    static IDictionary<string, object> CastDictionary(dynamic arg)
    {
        return arg as IDictionary<string, object>;
    }
}

static class Extensions
{
    public static T Get<T>(this IDictionary<string, object> dictionary, string key)
    {
        var value = dictionary[key];
        if (value is T)
            return (T)value;
        throw new InvalidOperationException();
    }
}

The exception: Microsoft.CSharp.RuntimeBinder.RuntimeBinderException was unhandled HResult=-2146233088 Message='System.Collections.Generic.Dictionary<string,object>' does not contain a definition for 'Get' Source=Anonymously Hosted DynamicMethods Assembly StackTrace: at CallSite.Target(Closure , CallSite , Object , String ) at System.Dynamic.UpdateDelegates.UpdateAndExecute2[T0,T1,TRet](CallSite site, T0 arg0, T1 arg1) at DynamicBug.Program.MethodUsesImplicitDeclaration(Object reallyDictionary) in c:\TFS\UnreleasedCode\POC\DynamicBug\DynamicBug\Program.cs:line 28 at DynamicBug.Program.Main(String[] args) in c:\TFS\UnreleasedCode\POC\DynamicBug\DynamicBug\Program.cs:line 16 InnerException:

like image 375
Jason Mowry Avatar asked Jul 15 '14 14:07

Jason Mowry


People also ask

What are bugs in C?

In computer technology, a bug is a coding error in a computer program. (We consider a program to also include the microcode that is manufactured into a microprocessor.) The process of finding bugs -- before users do -- is called debugging.


1 Answers

The problem is that when you don't explicitly assigned the object to a IDictionary<string,object> declaration, the object will still be a dynamic type (see the type resolution of in the images).

As Eric Lippert points out in https://stackoverflow.com/a/5313149/1039903 extension methods will not be available at the call site, for dynamic types:

To expand on Jon's answer, the reason this doesn't work is because in regular, non-dynamic code extension methods work by doing a full search of all the classes known to the compiler for a static class that has an extension method that match. The search goes in order based on the namespace nesting and available "using" directives in each namespace.

That means that in order to get a dynamic extension method invocation resolved correctly, somehow the DLR has to know at runtime what all the namespace nestings and "using" directives were in your source code. We do not have a mechanism handy for encoding all that information into the call site. We considered inventing such a mechanism, but decided that it was too high cost and produced too much schedule risk to be worth it.

I loaded your code up into a test method to show you what is actually resolved in var dictionary during runtime compared to an explicit declaration.

Explicit declaration:

enter image description hereenter image description here

Implicit declaration

enter image description hereenter image description here

If you take a look at the Type resolution of dictionary the explicit declaration has type System.Collection.Generic.IDictionary and the implicit declaration has type dynamic{System.Collections.Generic.Dictionary}

like image 130
wbennett Avatar answered Oct 29 '22 16:10

wbennett