CSharp binder does not use dynamic object's binding

Jan 18, 2010 at 11:19 AM

Hi 

My understanding is that if an object is a dynamic object, then the binder will let it do the binding. However, I found that the CSharpInvokeMemberBinder does not use a DynamicObject's TryInvokeMember method to do the binding in some cases. Here's an example.

Say we have a class Car like this:

public class Car : DynamicObject 
{
    public int Foo() { return 5; }

    public override bool TryInvokeMember(...) { ... }
}

If I use the class Car like this:

dynamic car = new Car();
int foo = car.Foo();
int bar = car.Bar();
Then what I observed is that the call to Foo will not lead to a call to the TryInvokeMember method in Car. On the other hand, the call to Bar will lead to a call to the TryInvokeMember method. 
This behavior does not seem to be consistent with the idea that 'object is king' as it is said in one of the DLR documents. Is the behavior by design? If so, why? 
Thanks,
Gary

 


 

 

 

Jan 18, 2010 at 2:45 PM

Yes, this behavior is by design. Don't forget that "DynamicObject" is just a useful helper class which is designed to make it easy to implement objects with dynamic behavior from C# -- it's not actually a core implementation class for dynamic behavior.

The source code for DynamicObject can be downloaded either from this (DLR) site or as part of IronPython. Reading it should be instructive. CallMethodWithResult is the single method most responsible for the behavior in question. There's one particular comment which deserves your attention:

// Now, call fallback again using our new MO as the error
// When we do this, one of two things can happen:
//   1. Binding will succeed, and it will ignore our call to
//      the dynamic method, OR
//   2. Binding will fail, and it will use the MO we created
//      above.

The "fallback" in this case refers to the default behavior as defined by the language using your object. So basically, the C# runtime binder always gets first crack at dispatch for DynamicObject. Only if it fails will the dynamic behavior be invoked. If you don't waht this behavior -- if you want full control over dispatch -- you would need to define your own DynamicMetaObject and return that from your IDynamicMetaObjectProvider implementation.

But the simplest way to prevent the behavior you describe is simply to make the implementation of "Foo" private. Then the C# runtime binder won't see it, and your implementation of TryInvokeMember will always be called.

Coordinator
Jan 18, 2010 at 9:44 PM

The high-level here is that it is an explicit scenario to let static members on the .NET subclass of DynamicObj bind more efficiently.  Section 3.2 of the library-authors-introduction.doc on the DLR docs page talks about this a little.  Early feedback on DynObj was that people wanted to put some regular .NET members on their subclasses and not have to have a big switch in their Try… methods for calling on themselves.

Cheers,

Bill

From: CurtHagenlocher [mailto:notifications@codeplex.com]
Sent: Monday, January 18, 2010 6:46 AM
To: Bill Chiles
Subject: Re: CSharp binder does not use dynamic object's binding [dlr:81163]

From: CurtHagenlocher

Yes, this behavior is by design. Don't forget that "DynamicObject" is just a useful helper class which is designed to make it easy to implement objects with dynamic behavior from C# -- it's not actually a core implementation class for dynamic behavior.

The source code for DynamicObject can be downloaded either from this (DLR) site or as part of IronPython. Reading it should be instructive. CallMethodWithResult is the single method most responsible for the behavior in question. There's one particular comment which deserves your attention:

// Now, call fallback again using our new MO as the error
// When we do this, one of two things can happen:
//   1. Binding will succeed, and it will ignore our call to
//      the dynamic method, OR
//   2. Binding will fail, and it will use the MO we created
//      above.

The "fallback" in this case refers to the default behavior as defined by the language using your object. So basically, the C# runtime binder always gets first crack at dispatch for DynamicObject. Only if it fails will the dynamic behavior be invoked. If you don't waht this behavior -- if you want full control over dispatch -- you would need to define your own DynamicMetaObject and return that from your IDynamicMetaObjectProvider implementation.

But the simplest way to prevent the behavior you describe is simply to make the implementation of "Foo" private. Then the C# runtime binder won't see it, and your implementation of TryInvokeMember will always be called.

Read the full discussion online.

To add a post to this discussion, reply to this email (dlr@discussions.codeplex.com)

To start a new discussion for this project, email dlr@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe or change your settings on codePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at codeplex.com

Jan 19, 2010 at 3:24 AM

Great information. Just what I was looking to know! Thanks!