Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does every distinct dynamic invocation result in two exceptions, and can these be suppressed?

Consider the following:

using System;
using System.Dynamic;
using System.Linq;

namespace DynamicObjectTest
{
    class Program
    {
        static void Main(string[] args)
        {
            dynamic dyn = new TestDynamic();
            Console.ReadKey();

            foreach (var i in Enumerable.Range(0, 100))
            {
                Console.WriteLine(dyn.Foo());
                Console.WriteLine(dyn.Bar());
            }

            Console.ReadKey();
        }
    }

    class TestDynamic : DynamicObject
    {
        public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
        {
            if (binder.Name == "Foo")
            {
                result = "Bar";
                return true;
            }
            else if (binder.Name == "Bar")
            {
                result = "Foo";
                return true;
            }

            return base.TryInvokeMember(binder, args, out result);
        }
    }
}

When running this program, four exceptions of type RuntimeBinderException are thrown. You can observe this either by breaking on all thrown exceptions (Debug/Exceptions.../check the Common Language Runtime Exceptions Throw checkbox) or by using perfmon:

enter image description here

Now these exceptions are obviously caught and handled internally because the TryInvokeMember method is called afterwards. However, it seems heavy-handed and an inappropriate use of exceptions if you subscribe to the "use exceptions only in exceptional circumstances" mantra. For my specific example it's not really a problem because the same members - Foo and Bar - are repeatedly invoked. However, I have other scenarios in mind where the members are far less static.

Is there anything that can be done to help the runtime invoke TryInvokeMember without throwing any exceptions?

like image 459
Kent Boogaart Avatar asked Nov 16 '11 12:11

Kent Boogaart


1 Answers

The system sometimes throws and catches exceptions internally. There is nothing you can do (except submit feedback to http://connect.microsoft.com/VisualStudio but there is no basis since this is unlikely to affect performance -- other overhead related to DynamicObject greatly exceeds this).

(If I had to guess, internally this might be like the memory "page fault" hardware exception: the system allows the exception to occur, then catches it and brings things together so that the future execution succeeds. This technique can be extremely efficient since it makes use of the CPU's exception features so that no conditional branching is needed in the code.)

NOTE: To try out the code in the original post, be sure to turn off the "Just My Code" option as well as configuring to break on all thrown exceptions.

like image 85
Jason Kresowaty Avatar answered Oct 10 '22 18:10

Jason Kresowaty