Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unpredictible behaviour in c# dynamic

Tags:

c#

dynamic

I've found a bug (feature?) during learning dynamic in C#. Can anyone explain me, why do I have an exception??

static class Program
{
    public static void Main(string[] args)
    {
        dynamic someObj = ConstructSomeObj((Action)(() => Console.WriteLine("wtf")));

        var executer = someObj.Execute;
        executer();         // shows "wtf"
        someObj.Execute();  // throws RuntimeBinderException 

        Console.ReadKey();
    }

    static dynamic ConstructSomeObj(dynamic param) 
        => new { Execute = param };
}

Note: typeof both exectuer and someObj is dynamic

like image 881
Vakun Avatar asked Jun 30 '16 05:06

Vakun


People also ask

What are undefined behavior in C?

So, in C/C++ programming, undefined behavior means when the program fails to compile, or it may execute incorrectly, either crashes or generates incorrect results, or when it may fortuitously do exactly what the programmer intended.

Why does C allow undefined behavior?

It exists because of the syntax rules of C where a variable can be declared without init value. Some compilers assign 0 to such variables and some just assign a mem pointer to the variable and leave just like that. if program does not initialize these variables it leads to undefined behavior.

What is Behaviour in C?

In C FAQs this behaviour is defined as: “Anything at all can happen; the standard imposes no requirements. The program may fail to compile, or it may execute incorrectly (either crashing or silently generating incorrect results), or it may fortuitously do exactly what the programmer intended.”

What happens undefined behavior?

In computer programming, undefined behavior (UB) is the result of executing a program whose behavior is prescribed to be unpredictable, in the language specification to which the computer code adheres.


1 Answers

Let's look at following code:

using System;
using System.Collections.Generic;


public class Program
{
    public static void Main(string[] args)
    {
        Console.WriteLine("first");

        // works perfectly!!!
        dynamic foo = new { x=(Action)(() => Console.WriteLine("ok")) };
        foo.x();

        // fails
        dynamic foo2 = new { x=(object)(Action)(() => Console.WriteLine("ok2")) };
        foo2.x();

    }
}

dynamic uses reflection to access objects method and fields and since it cannot know exact types it must rely on type information present in objects on which it operate.

When field x in anonymous type is properly typed as delegate invocation foo.x() works because dynamic can see that field value is delegate.

When you use

static dynamic ConstructSomeObj(dynamic param) 
    { return new { x = param }; }

to create anonymous class you created class with field x of type object (dynamic is object behind the scenes). When you call obj.x dynamic sees that field type is an object and it does't bother to check to what exact type this field points. And since object doesn't have Invoke() method like delegates it throws exception. If you change method parameter type to Action it will work.

I guess this decision to check field type instead of type of value that field contains was taken to provide better performance. In other words when you check field type CallSite class generated by dynamic can be cached and reused later.

References: https://github.com/mono/mono/blob/ef407901f8fdd9ed8c377dbec8123b5afb932ebb/mcs/class/Microsoft.CSharp/Microsoft.CSharp.RuntimeBinder/Binder.cs

https://github.com/mono/mono/blob/ef407901f8fdd9ed8c377dbec8123b5afb932ebb/mcs/class/Microsoft.CSharp/Microsoft.CSharp.RuntimeBinder/CSharpInvokeMemberBinder.cs

EDIT: Checked this on mono, can somebody verify on VS

like image 65
csharpfolk Avatar answered Oct 10 '22 01:10

csharpfolk