7

Ran into an interesting runtime issue after some refactoring and have pinned in down to the following situation.

When passing a property from a dynamic object to a method on an Interface that has been inherited from a parent interface the runtime binder cannot find the method.

Here is a test to demonstrate both failure and success (when calling method directly on the parent interface type)

using System.Dynamic;
using Microsoft.CSharp.RuntimeBinder;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Test.Utility
{
    public interface IEcho
    {
        string EchoString(string input);
    }

    public interface IInheritEcho : IEcho
    { }

    public class EchoClass : IInheritEcho
    {
        public string EchoString(string input)
        {
            return input;
        }
    }

    [TestClass]
    public class RuntimeBinderTest
    {
        [TestMethod]
        public void RuntimeBinder_should_work_when_dynamic_parameters_are_passed_to_method_from_inherited_interface()
        {
            //Arrange
            dynamic dynObject = new ExpandoObject();
            dynObject.Foo = "Bar";
            IInheritEcho echomore = new EchoClass();

            string echo = null;
            string exceptionMessage = null;

            //Act
            try
            {
                echo = echomore.EchoString(dynObject.Foo);
            }
            catch (RuntimeBinderException e)
            {
                exceptionMessage = e.Message;
            }

            //Assert
            Assert.AreEqual(echo, dynObject.Foo, false, exceptionMessage);
        }

        [TestMethod]
        public void RuntimeBinder_should_work_when_dynamic_parameters_are_passed_to_method_from_noninherited_interface()
        {
            //Arrange
            dynamic dynObject = new ExpandoObject();
            dynObject.Foo = "Bar";
            IEcho echomore = new EchoClass();

            string echo = null;
            string exceptionMessage = null;

            //Act
            try
            {
                echo = echomore.EchoString(dynObject.Foo);
            }
            catch (RuntimeBinderException e)
            {
                exceptionMessage = e.Message;
            }

            //Assert
            Assert.AreEqual(echo, dynObject.Foo, false, exceptionMessage);
        }
    }
}

Test #1 Fails: Assert.AreEqual failed. Expected:<(null)>. Actual:. 'Test.Utility.IInheritEcho' does not contain a definition for 'EchoString'

Test #2 Succeeds.

My question is whether my assumption that the 1st test should pass is correct or is there a fundamental reason in the framework that it does not?

I know I can fix the issue by casting the parameters when I pass them in or assigning them to variables before passing them in. I'm more just curious as to the reason the inherited interface is causing the RuntimeBinder to fail...

3
  • You're completely right. (Although it's of an older c# version: msdn.microsoft.com/en-us/library/aa664578%28VS.71%29.aspx) There must be a failure. What if you use a regular class with a string property instead of the expando object? Does it find the method in the inherited interface? (Don't have VS here to make the test myself). If it was with static binding (compile time binding), then there's something wrong with the dynamic binder (run time binder). Commented May 10, 2012 at 10:16
  • Using a regular class with a string property passes as expected. It's definitely the runtime binder that is not behaving... Commented May 10, 2012 at 11:20
  • If you look at igofed's answer link to Microsof Connect, this bug is knwon and most probably won't be solved in the new VS version. Commented May 10, 2012 at 11:31

2 Answers 2

4

You situations is a documented bug on Microsoft Connect

Sign up to request clarification or add additional context in comments.

3 Comments

So a known issue. Follows through to this question which is a good discussion on the issue
FYI, for anyone finding this again through google, the final judgement by Microsoft on this bug is "closed as won't fix" on 4/6/2011 due to it being "scoped out." boo. :(
And five years later it's still out of scope?
2

A good question this.

It would appear that it's taking the type of the expression at compile time, IInheritEcho, and not deep-searching the members of inherited interfaces when looking for the method to invoke dynamically.

And ideally the C# runtime binder for a dynamic expression should behave the same way as the C# compiler - therefore it should see that the IEcho interface is inherited by IInheritEcho and it should work.

We can test the hypothesis - i.e. that it's the static typing - by doing this in the first test:

echo = ((dynamic)echomore).EchoString(dynObject.Foo);

Hey presto - the test passes.

So the issue is not that the dynamic binder can't find the method - it's that when the instance whose member is being invoked dynamically is statically typed as an interface, inherited interfaces are not consulted.

In my opinion this behaviour is incorrect.

Please Eric Lippert... be nice...

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.