C#的动态对象的属性实现比较简单,如果要实现动态语言那种动态方法就比较困难,因为对于dynamic对象,扩展方法,匿名方法都是不能用直接的,这里还是利用对象和委托来模拟这种动态方法的实现,看起来有点javascript的对象味道:
1)定义一个委托,参数个数可变,参数都是object类型:这里的委托多有个dynamic参数,代表调用这个委托的动态对象本身.
publicdelegateobjectMyDelegate(dynamic Sender,paramsobject[] PMs);
public delegate object MyDelegate(dynamic Sender, params object[] PMs);
2)定义一个委托转载对象,因为dynamic对象不能直接用匿名方法,这里用对象去承载:
publicclassDelegateObj
{
privateMyDelegate _delegate;
publicMyDelegate CallMethod
{
get{return_delegate; }
}
privateDelegateObj(MyDelegate D)
{
_delegate = D;
}
///
/// 构造委托对象,让它看起来有点javascript定义的味道.
///
///
///
publicstaticDelegateObj Function(MyDelegate D)
{
returnnewDelegateObj(D);
}
}
public class DelegateObj
{
private MyDelegate _delegate;
public MyDelegate CallMethod
{
get { return _delegate; }
}
private DelegateObj(MyDelegate D)
{
_delegate = D;
}
///
/// 构造委托对象,让它看起来有点javascript定义的味道.
///
///
///
public static DelegateObj Function(MyDelegate D)
{
return new DelegateObj(D);
}
}
3) 定义一个动态对象:
publicclassDynObj : DynamicObject
{
//保存对象动态定义的属性值
privateDictionary _values;
publicDynObj()
{
_values = newDictionary();
}
///
/// 获取属性值
///
///
///
publicobjectGetPropertyValue(stringpropertyName)
{
if(_values.ContainsKey(propertyName) ==true)
{
return_values[propertyName];
}
returnnull;
}
///
/// 设置属性值
///
///
///
publicvoidSetPropertyValue(stringpropertyName,objectvalue)
{
if(_values.ContainsKey(propertyName) ==true)
{
_values[propertyName] = value;
}
else
{
_values.Add(propertyName, value);
}
}
///
/// 实现动态对象属性成员访问的方法,得到返回指定属性的值
///
///
///
///
publicoverrideboolTryGetMember(GetMemberBinder binder,outobjectresult)
{
result = GetPropertyValue(binder.Name);
returnresult ==null?false:true;
}
///
/// 实现动态对象属性值设置的方法。
///
///
///
///
publicoverrideboolTrySetMember(SetMemberBinder binder,objectvalue)
{
SetPropertyValue(binder.Name, value);
returntrue;
}
///
/// 动态对象动态方法调用时执行的实际代码
///
///
///
///
///
publicoverrideboolTryInvokeMember(InvokeMemberBinder binder,object[] args,outobjectresult)
{
var theDelegateObj = GetPropertyValue(binder.Name) asDelegateObj;
if(theDelegateObj ==null|| theDelegateObj.CallMethod ==null)
{
result = null;
returnfalse;
}
result = theDelegateObj.CallMethod(this,args);
returntrue;
}
publicoverrideboolTryInvoke(InvokeBinder binder,object[] args,outobjectresult)
{
returnbase.TryInvoke(binder, args,outresult);
}
}
public class DynObj : DynamicObject
{
//保存对象动态定义的属性值
private Dictionary _values;
public DynObj()
{
_values = new Dictionary();
}
///
/// 获取属性值
///
///
///
public object GetPropertyValue(string propertyName)
{
if (_values.ContainsKey(propertyName) == true)
{
return _values[propertyName];
}
return null;
}
///
/// 设置属性值
///
///
///
public void SetPropertyValue(string propertyName,object value)
{
if (_values.ContainsKey(propertyName) == true)
{
_values[propertyName] = value;
}
else
{
_values.Add(propertyName, value);
}
}
///
/// 实现动态对象属性成员访问的方法,得到返回指定属性的值
///
///
///
///
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = GetPropertyValue(binder.Name);
return result == null ? false : true;
}
///
/// 实现动态对象属性值设置的方法。
///
///
///
///
public override bool TrySetMember(SetMemberBinder binder, object value)
{
SetPropertyValue(binder.Name, value);
return true;
}
///
/// 动态对象动态方法调用时执行的实际代码
///
///
///
///
///
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
var theDelegateObj = GetPropertyValue(binder.Name) as DelegateObj;
if (theDelegateObj == null || theDelegateObj.CallMethod == null)
{
result = null;
return false;
}
result = theDelegateObj.CallMethod(this,args);
return true;
}
public override bool TryInvoke(InvokeBinder binder, object[] args, out object result)
{
return base.TryInvoke(binder, args, out result);
}
}
应用测试代码:
dynamic theObj =newDynObj();
theObj.aaa = "this is a test";//动态属性
//动态方法,这里不能没法定义参数,调用的时候可以是任意多参数,具体参数类型和含义就只能自己去小心处理了.
theObj.show = DelegateObj.Function((s, pms) =>
{
if(pms !=null&& pms.Length > 0)
{
MessageBox.Show(pms[0].ToString() + ":"+ s.aaa);
}
else
{
MessageBox.Show(s.aaa);
}
returnnull;
}
);
theObj.show("hello");
dynamic theObj = new DynObj();
theObj.aaa = "this is a test";//动态属性
//动态方法,这里不能没法定义参数,调用的时候可以是任意多参数,具体参数类型和含义就只能自己去小心处理了.
theObj.show = DelegateObj.Function((s, pms) =>
{
if (pms != null && pms.Length > 0)
{
MessageBox.Show(pms[0].ToString() + ":" + s.aaa);
}
else
{
MessageBox.Show(s.aaa);
}
return null;
}
);
theObj.show("hello");
虽然看起来上面有点Js定义对象方法的味道,但由于C#是静态语言,提供的动态模拟机制还是有限的,看起来是动态,但所有的值存放和方法都需要自己写代码去处理.
以上代码在vs2010,windows 2008 server,框架4.0 上测试OK.