Alex Rivera | Logout

How do I express a void method call as the result of DynamicMetaObject.BindInvokeMember?

Asked 2009-12-02T21:22:27.870
57

I'm trying to give a short example of IDynamicMetaObjectProvider for the second edition of C# in Depth, and I'm running into issues.

I want to be able to express a void call, and I'm failing. I'm sure it's possible, because if I dynamically call a void method using the reflection binder, all is fine. Here's a short but complete example:

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

class DynamicDemo : IDynamicMetaObjectProvider
{
    public DynamicMetaObject GetMetaObject(Expression expression)
    {
        return new MetaDemo(expression, this);
    }

    public void TestMethod(string name)
    {
        Console.WriteLine(name);
    }

}

class MetaDemo : DynamicMetaObject
{
    internal MetaDemo(Expression expression, DynamicDemo demo)
        : base(expression, BindingRestrictions.Empty, demo)
    {
    }

    public override DynamicMetaObject BindInvokeMember
        (InvokeMemberBinder binder, DynamicMetaObject[] args)
    {
        Expression self = this.Expression;

        Expression target = Expression.Call
            (Expression.Convert(self, typeof(DynamicDemo)),
             typeof(DynamicDemo).GetMethod("TestMethod"),
             Expression.Constant(binder.Name));

        var restrictions = BindingRestrictions.GetTypeRestriction
            (self, typeof(DynamicDemo));

        return new DynamicMetaObject(target, restrictions);
    }
}

class Test
{
    public void Foo()
    {
    }

    static void Main()
    {
        dynamic x = new Test();
        x.Foo(); // Works fine!

        x = new DynamicDemo();
        x.Foo(); // Throws
    }
}

This throws an exception:

Unhandled Exception: System.InvalidCastException: The result type 'System.Void' of the dynamic binding produced by the object with type 'DynamicDemo' fo

Edit
Report

1 Answer

26

This is similar to:

DLR return type

You do need to match the return type specified by the ReturnType property. For all of the standard binaries this is fixed to object for almost everything or void (for the deletion operations). If you know you're making a void call I'd suggest wrapping it in:

Expression.Block(
    call,
    Expression.Default(typeof(object))
);

The DLR used to be quite lax about what it would allow and it would provide some minimal amount of coercion automatically. We got rid of that because we didn't want to provide a set of convensions which may or may not have made sense for each language.

It sounds like you want to prevent:

dynamic x = obj.SomeMember();

There's no way to do that, there'll always be a value returned that the user can attempt to continue to interact with dynamically.

answered 2009-12-02T23:20:54.180

Your Answer