Why a Microsoft.CSharp.RuntimeBinder.RuntimeBinderException if the invoked method is there?

lontivero picture lontivero · Apr 15, 2011 · Viewed 44.5k times · Source

I have the following code which creates a dynamic object that is assigned to the smtpClient variable.

public class TranferManager
{
    public void Tranfer(Account from, Account to, Money amount)
    {
        // Perform the required actions
        var smtpClient = New.SmtpClient();
        smtpClient.Send("[email protected]", "from.Email", "Tranfer", "?");
        // In the previous line I get a Microsoft.CSharp.RuntimeBinder.RuntimeBinderException
        // with the description = "'object' does not contain a definition for 'Send'"
    }
}

public static class New
{
    public static dynamic SmtpClient(params object[] parameters)
    {
        return typeof(SmtpClient).New(parameters);
    }
}

public static class CreationExtensions
{
    private static Dictionary<Type, Func<object, dynamic>> builders =
        new Dictionary<Type, Func<object, dynamic>>();

    public static dynamic New(this Type type, params object[] parameters)
    {
        if(builders.ContainsKey(type))
            return builders[type](parameters);

        return Activator.CreateInstance(type, parameters);
    }

    public static void RegisterBuilder(this Type type, Func<object, dynamic> builder)
    {
        builders.Add(type, builder);
    }
}

To test it I am using the UT (below):

    [TestMethod()]
    public void TranferTest()
    {
        typeof(SmtpClient).RegisterBuilder(p => 
            new
            {
                Send = new Action<string, string, string, string>(
                (from, to, subject, body) => { })
            }
        );

        var tm = new TranferManager();
        tm.Tranfer(new Account(), new Account(), new Money());
        // Assert
    }

When I, using the inmediate windows, ask for the smtpClient type I get:

smtpClient.GetType()
{<>f__AnonymousType0`1[System.Action`4[System.String,System.String,System.String,System.String]]}

And when I ask for its members I get:

smtpClient.GetType().GetMembers()
{System.Reflection.MemberInfo[7]}
    [0]: {System.Action`4[System.String,System.String,System.String,System.String] get_Send()}
    [1]: {System.String ToString()}
    [2]: {Boolean Equals(System.Object)}
    [3]: {Int32 GetHashCode()}
    [4]: {System.Type GetType()}
    [5]: {Void .ctor(System.Action`4[System.String,System.String,System.String,System.String])}
    [6]: {System.Action`4[System.String,System.String,System.String,System.String] Send}

So, my question is: Why am I getting that exception?

Answer

jbtule picture jbtule · Jun 10, 2011

Anonymous types are internal, if you cross assembly boundaries dynamic can't resolve the property.

Rather than using an anonymous type, try using an actual type or an Expando Object.