C# Dynamic之:ExpandoObject,DynamicObject,DynamicMetaOb的应用(下)
接上文:c# dynamic关键字之:expandoobject,dynamicobject,dynamicmetaob的应用(上)
为什么tryxxx方法没有被调用??
将dynamicproduct 中的name修饰符改为private:
private string name;
可以在trysetmember方法中设置断点,再次运行:
为什么访问修饰符是public不调用trysetmember,是private 就调用了呢??
难道是因为private抛出了异常吗??
再次看看msdn对此的trysetmember方法的解释:
msdn备注
…………….动态语言运行库 (dlr) 将首先使用语言联编程序在类中查找属性的静态定义。 如果没有此类属性,dlr 调用 trysetmember 方法。
问题的原因是这样的:首先dlr 使用语言联编程序在类中查找name的静态定义,
因为name是public,所以查找到了,然后返回,不会去调用trysetmember方法了,
但是如果name是private,那么联编程序在类中没找到name的静态定义,于是dlr尝试调用trysetmember方法。
修改trysetmember方法如下:
public override bool trysetmember(setmemberbinder binder, object value)
{
console.writeline("trysetmember被调用了,name:{0}", binder.name);
bool result = base.trysetmember(binder, value);
return true;
}
运行,可以发现不会抛出异常了:
总结:首先dlr会尝试查找属性的静态定义,如果没有找到则会调用相应的tryxxx 方法,如果tryxxx方法返回false,代表tryxxx方法运行失败,dlr随后会抛出异常。
为了验证是不是这样,将dynamicproduct中属性的静态定义全部注释掉,并且tryxxx方法全部返回true。完整的代码如下:
class dynamicproduct : dynamicobject
{
#region dynamicproduct 的一些属性的静态定义
//private string name;
//public int id { get; set; }
//public void showproduct()
//{
// console.writeline("id={0} ,name={1}", id, name);
//}
#endregion
#region override dynamicobject 的方法
public override bool trygetmember(getmemberbinder binder, out object result)
{
console.writeline("trygetmember被调用了,name:{0}", binder.name);
bool tryresult = base.trygetmember(binder, out result);
return true;
}
public override bool trysetmember(setmemberbinder binder, object value)
{
console.writeline("trysetmember被调用了,name:{0}", binder.name);
bool tryresult = base.trysetmember(binder, value);
return true;
}
public override bool tryinvoke(invokebinder binder, object[] args, out object result)
{
console.writeline("tryinvoke被调用了");
bool tryresult = base.tryinvoke(binder, args, out result);
return true;
}
public override bool tryinvokemember(invokememberbinder binder, object[] args, out object result)
{
console.writeline("tryinvokemember被调用了,name:{0}", binder.name);
bool tryresult = base.tryinvokemember(binder, args, out result);
return true;
}
#endregion
}
main方法不变:
static void main(string[] args)
{
dynamic dynproduct = new dynamicproduct();
dynproduct.name = "n1"; //调用trysetmember方法
dynproduct.id = 1;
dynproduct.id = dynproduct.id + 3;
dynproduct.showproduct();
console.readline();
}
运行,结果如下:
d.p3 = d.m1(d.p1, d.m2(d.p2));
按照从左到右,从里到外的原则。
1:先调用d.p1,dlr会尝试调用d 的getmetaobject 方法,此方法返回一个mymetaobject对象。
接着dlr知道你调用的是一个属性,于是它调用返回的mymetaobject对象的bindgetmember 方法,
输出为getmember of property p1
2:调用d.p2,和调用d.p1 一样.
3:调用d.m2,同样dlr调用d的getmetaobject方法,返回一个mymetaobject对象,接着调用返回对象的bindinvokemember 方法。