Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should an expression of type ‘dynamic’ behave the same way at run-time as a non-dynamic one of the same run-type time?

Tags:

c#

dynamic

Consider the following example program:

using System;
public delegate string MyDelegateType(int integer);

partial class Program
{
    static string MyMethod(int integer) { return integer.ToString(); }

    static void Main()
    {
        Func<int, string> func = MyMethod;

        // Scenario 1: works
        var newDelegate1 = new MyDelegateType(func);
        newDelegate1(47);

        // Scenario 2: doesn’t work
        dynamic dyn = func;
        var newDelegate2 = new MyDelegateType(dyn);
        newDelegate2(47);
    }
}

The first one works as expected — the conversion to MyDelegateType succeeds. The second one, however, throws a RuntimeBinderException with the error message:

Cannot implicitly convert type 'System.Func<int,string>' to 'MyDelegateType'

Is there anything in the C# specification that allows for this behaviour, or is this a bug in Microsoft’s C# compiler?

like image 220
Timwi Avatar asked Sep 12 '11 17:09

Timwi


2 Answers

Good catch Timwi.

Our support for dynamic method groups is weak. For example, consider this simpler case:

class C
{
  public void M() {}
}

class P
{
    static void Main()
    {
        dynamic d = new C();
        C c = new C();
        Action a1 = c.M; // works
        Action a2 = d.M; // fails at runtime

The d.M is interpreted as a property get (or field access) by the dynamic runtime, and when it resolves as a method group, it fails at runtime.

The same thing is happening in your case, it is just a bit more obscure. When you say MyDelegate x = new MyDelegate(someOtherDelegate); that is treated by the compiler just as if you'd said MyDelegate x = someOtherDelegate.Invoke;. The dynamic runtime piece does not know to do that transformation, and even if it did, it couldn't handle resolving the method group that is the result of the .Invoke portion of the expression.

Is there anything in the C# specification that allows for this behaviour, or is this a bug in Microsoft’s C# compiler?

The spec does not call out that this should be a runtime error, and does imply that it should be handled correctly at runtime; clearly the implementation does not do so. Though it is a shortcoming of the implementation I wouldn't call this a "bug" because we deliberately made the behaviour you've discovered. We did not have the resources to make these kinds of expressions work exactly right, so we left them as errors. If we ever get a good way to represent method groups in the dynamic runtime, we might implement it.

Similarly there is no way in dynamic code to represent the notion of "this dynamic thing is a lambda expression where the types of the parameters are to be determined at runtime". If we have a good way to represent those in the future, we might do the work.

Sam talked a bit about this back in 2008; see his article on it:

http://blogs.msdn.com/b/samng/archive/2008/11/02/dynamic-in-c-ii-basics.aspx

like image 101
Eric Lippert Avatar answered Oct 23 '22 06:10

Eric Lippert


I've run in to this limitation too. Although I couldn't answer the why better than Eric Lippert, there is a straight forward workaround.

 var newDelegate2 = new MyDelegateType(x => dyn(x));

It implicitly gets the static signature from the delegate and the dynamic invocation works without any more info. This works for delegates and, as a bonus, dynamic callable objects.

like image 20
jbtule Avatar answered Oct 23 '22 07:10

jbtule