As you know if you read my blog, C# 4.0 introduced some language features that help you consume dynamic objects. Although it’s not part of the language, most of the writing about dynamic in C# that I have seen, including my own, also contains some point about how you create dynamic objects. And they usually make it clear that the easiest way to do that is to extend System.Dynamic.DynamicObject. For instance, you might see an example such as the following, which is pretty straight-forward: using System;
using System.Dynamic;class MyDynamicObject : DynamicObject
{
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
Console.WriteLine("You called method {0}!", binder.Name);
Console.WriteLine("... and passed {0} args.", args.Length);
result = null;
return true;
}
}class Program
{
static void Main(string[] args)
{
dynamic d = new MyDynamicObject();
d.Foo(d, 1, "bar");
}
}... that prints:You called method Foo!
... and passed 3 args.That’s all well and good. But I want to tell you that although this works and is easy, DynamicObject is not a type that is specially known to the DLR, and that this is not the primary mechanism to define dynamic objects. The primary mechanism is to implement the interface IDynamicMetaObjectProvider, and to provide your own specialization of DynamicMetaObject. These two types are specially known to the DLR and they are the mechanism by which dynamic (including DynamicObject) really works. DynamicObject is a tool of convenience. You could write it yourself, if you wanted to. The design of DynamicObject deliberately introduces some trade-offs in the name of ease-of-use, and if your code or library is not OK with those trade-offs, then you should consider your alternatives. Binding vs. executing
One thing that DynamicObject does to your dynamic objects is that it confuses two separate “phases” of the execution of a dynamic operation. There is a lot of machinery in the DLR that is designed to make your dynamic operations fast, and there are concepts called “call sites” and “rules” and “binders,” etc., and you can dig into this yourself if it’s important, but the upshot is: when a dynamic operation is bound at runtime, the binding is cached using something called a “rule” that indicates the circumstances under which to execute some code, as well as the code to execute. Subsequent to the binding, the code the binding produced is simply run when needed. Read more: Chris Burrows' Blog
using System.Dynamic;class MyDynamicObject : DynamicObject
{
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
Console.WriteLine("You called method {0}!", binder.Name);
Console.WriteLine("... and passed {0} args.", args.Length);
result = null;
return true;
}
}class Program
{
static void Main(string[] args)
{
dynamic d = new MyDynamicObject();
d.Foo(d, 1, "bar");
}
}... that prints:You called method Foo!
... and passed 3 args.That’s all well and good. But I want to tell you that although this works and is easy, DynamicObject is not a type that is specially known to the DLR, and that this is not the primary mechanism to define dynamic objects. The primary mechanism is to implement the interface IDynamicMetaObjectProvider, and to provide your own specialization of DynamicMetaObject. These two types are specially known to the DLR and they are the mechanism by which dynamic (including DynamicObject) really works. DynamicObject is a tool of convenience. You could write it yourself, if you wanted to. The design of DynamicObject deliberately introduces some trade-offs in the name of ease-of-use, and if your code or library is not OK with those trade-offs, then you should consider your alternatives. Binding vs. executing
One thing that DynamicObject does to your dynamic objects is that it confuses two separate “phases” of the execution of a dynamic operation. There is a lot of machinery in the DLR that is designed to make your dynamic operations fast, and there are concepts called “call sites” and “rules” and “binders,” etc., and you can dig into this yourself if it’s important, but the upshot is: when a dynamic operation is bound at runtime, the binding is cached using something called a “rule” that indicates the circumstances under which to execute some code, as well as the code to execute. Subsequent to the binding, the code the binding produced is simply run when needed. Read more: Chris Burrows' Blog
0 comments:
Post a Comment