Answers:
该dynamic关键字用于声明应该后期绑定变量。
如果要对任何实类型或想象中的类型使用后期绑定,请使用dynamic关键字,其余的由编译器完成。
当您使用dynamic关键字与普通实例进行交互时,DLR将对实例的普通方法执行后期绑定调用。
该IDynamicMetaObjectProvider接口允许类控制其后期行为。
当您使用dynamic关键字与IDynamicMetaObjectProvider实现交互时,DLR会调用IDynamicMetaObjectProvider方法,而对象本身将决定要执行的操作。
在ExpandoObject和DynamicObject类的实现IDynamicMetaObjectProvider。
ExpandoObject是一个简单的类,它允许您将成员添加到实例并使用它们dynamic。
DynamicObject是一种更高级的实现,可以继承以轻松提供自定义行为。
我将尝试为该问题提供一个更清晰的答案,以清楚地解释动态ExpandoObject和之间的区别DynamicObject。
很快,dynamic就是一个关键字。它本身不是类型。它是一个关键字,告诉编译器在设计时忽略静态类型检查,而在运行时使用后期绑定。因此,dynamic在此答案的其余部分中,我们不会花很多时间。
ExpandoObject并且DynamicObject确实是类型。在表面上,它们看起来非常相似。这两个类都实现IDynamicMetaObjectProvider。但是,深入研究,您会发现它们根本不相似。
DynamicObject是部分实现,IDynamicMetaObjectProvider纯粹是为了作为开发人员实现自己的自定义类型的起点,该自定义类型支持具有自定义基础存储和检索行为的动态调度,以使动态调度工作。
简而言之,当您要创建可与DLR一起使用并使用所需的任何CUSTOM行为的OWN类型时,请使用DynamicObject。
示例:假设您希望有一个动态类型,该动态类型在尝试对不存在的成员(即,在运行时未添加)进行get时返回一个自定义默认值。该默认值将显示“对不起,此罐子中没有cookie!”。如果希望动态对象具有这样的行为,则需要控制找不到字段时发生的情况。ExpandoObject不允许您执行此操作。因此,您需要使用独特的动态成员解析(调度)行为来创建自己的类型,并使用它来代替现成的类型ExpandoObject。
您可以按如下方式创建类型:(注意,以下代码仅用于说明目的,可能无法运行。要了解如何正确使用DynamicObject,请在其他地方找到许多文章和教程。)
public class MyNoCookiesInTheJarDynamicObject : DynamicObject
{
Dictionary<string, object> properties = new Dictionary<string, object>();
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if (properties.ContainsKey(binder.Name))
{
result = properties[binder.Name];
return true;
}
else
{
result = "I'm sorry, there are no cookies in this jar!"; //<-- THIS IS OUR
CUSTOM "NO COOKIES IN THE JAR" RESPONSE FROM OUR DYNAMIC TYPE WHEN AN UNKNOWN FIELD IS ACCESSED
return false;
}
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
properties[binder.Name] = value;
return true;
}
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
dynamic method = properties[binder.Name];
result = method(args[0].ToString(), args[1].ToString());
return true;
}
}
现在,我们可以将刚才创建的这个虚构类用作动态类型,如果该字段不存在,则具有非常自定义的行为。
dynamic d = new MyNoCookiesInTheJarDynamicObject();
var s = d.FieldThatDoesntExist;
//in our contrived example, the below should evaluate to true
Assert.IsTrue(s == "I'm sorry, there are no cookies in this jar!")
ExpandoObject是的完整实现IDynamicMetaObjectProvider。.NETFramework团队已为您做出所有这些决定。如果您不需要任何自定义行为,并且您觉得ExpandoObject对您来说足够好(90%的时间ExpandoObject就足够了),这很有用。因此,例如,请参见以下内容,对于ExpandoObject,设计人员选择了在动态成员不存在时抛出异常。
dynamic d = new ExpandoObject();
/*
The ExpandoObject designers chose that this operation should result in an
Exception. They did not have to make that choice, null could
have been returned, for example; or the designers could've returned a "sorry no cookies in the jar" response like in our custom class. However, if you choose to use
ExpandoObject, you have chosen to go with their particular implementation
of DynamicObject behavior.
*/
try {
var s = d.FieldThatDoesntExist;
}
catch(RuntimeBinderException) { ... }
综上所述,ExpandoObject这只是使用某些动态调度行为扩展DynamicObject的一种预先选择的方法,这可能对您有用,但可能并不取决于您的特定需求。
而DyanmicObjecthelper BaseType则使实现具有独特动态行为的自己的类型变得简单而容易。
DynamicObject:覆盖时TryGetMember,如果返回false,则RuntimeBinderException尝试访问不存在的属性时将抛出a 。为了使代码片段真正起作用,您应该返回true。
根据C#语言规范,dynamic是一个类型声明。即dynamic x表示变量x具有类型dynamic。
DynamicObject 是一种易于实现的类型 IDynamicMetaObjectProvider因此可以覆盖该类型的特定绑定行为。
ExpandoObject是一种类似于财产袋的类型。也就是说,您可以在运行时将属性,方法等添加到此类型的动态实例中。
dynamic不是实际的类型...只是提示,告诉编译器对此变量使用后期绑定。dynamic变量实际上是object在MSIL中声明的
上面的示例DynamicObject并没有清楚地表明区别,因为它基本上是在实现由ExpandoObject。
在下面提到的两个链接中,很明显,借助DynamicObject,可以保留/更改实际类型(XElement在下面的链接中使用的示例),并可以更好地控制属性和方法。
public class DynamicXMLNode : DynamicObject
{
XElement node;
public DynamicXMLNode(XElement node)
{
this.node = node;
}
public DynamicXMLNode()
{
}
public DynamicXMLNode(String name)
{
node = new XElement(name);
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
XElement setNode = node.Element(binder.Name);
if (setNode != null)
setNode.SetValue(value);
else
{
if (value.GetType() == typeof(DynamicXMLNode))
node.Add(new XElement(binder.Name));
else
node.Add(new XElement(binder.Name, value));
}
return true;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
XElement getNode = node.Element(binder.Name);
if (getNode != null)
{
result = new DynamicXMLNode(getNode);
return true;
}
else
{
result = null;
return false;
}
}
}