1. 程式人生 > >C#動態物件(dynamic)示例(實現方法和屬性的動態)

C#動態物件(dynamic)示例(實現方法和屬性的動態)

C#的動態物件的屬性實現比較簡單,如果要實現動態語言那種動態方法就比較困難,因為對於dynamic物件,擴充套件方法,匿名方法都是不能用直接的,這裡還是利用物件和委託來模擬這種動態方法的實現,看起來有點javascript的物件味道:

1)定義一個委託,引數個數可變,引數都是object型別:這裡的委託多有個dynamic引數,代表呼叫這個委託的動態物件本身.

public delegate object MyDelegate(dynamic Sender, params object[] PMs);


2)定義一個委託轉載物件,因為dynamic物件不能直接用匿名方法,這裡用物件去承載:

public class DelegateObj
    {
        private MyDelegate _delegate;

        public MyDelegate CallMethod
        {
            get { return _delegate; }
        }
        private DelegateObj(MyDelegate D)
        {
            _delegate = D;
        }
        /// <summary>
        /// 構造委託物件,讓它看起來有點javascript定義的味道.
        /// </summary>
        /// <param name="D"></param>
        /// <returns></returns>
        public static DelegateObj Function(MyDelegate D)
        {
            return new DelegateObj(D);
        }
    }

3) 定義一個動態物件:

public class DynObj : DynamicObject
    {
        //儲存物件動態定義的屬性值
        private Dictionary<string, object> _values;
        public DynObj()
        {
            _values = new Dictionary<string, object>();
        }
        /// <summary>
        /// 獲取屬性值
        /// </summary>
        /// <param name="propertyName"></param>
        /// <returns></returns>
        public object GetPropertyValue(string propertyName)
        {
            if (_values.ContainsKey(propertyName) == true)
            {
                return _values[propertyName];
            }
            return null;
        }
        /// <summary>
        /// 設定屬性值
        /// </summary>
        /// <param name="propertyName"></param>
        /// <param name="value"></param>
        public void SetPropertyValue(string propertyName,object value)
        {
            if (_values.ContainsKey(propertyName) == true)
            {
                _values[propertyName] = value;
            }
            else
            {
                _values.Add(propertyName, value);
            }
        }
        /// <summary>
        /// 實現動態物件屬性成員訪問的方法,得到返回指定屬性的值
        /// </summary>
        /// <param name="binder"></param>
        /// <param name="result"></param>
        /// <returns></returns>
        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            result = GetPropertyValue(binder.Name);
            return result == null ? false : true;
        }
        /// <summary>
        /// 實現動態物件屬性值設定的方法。
        /// </summary>
        /// <param name="binder"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public override bool TrySetMember(SetMemberBinder binder, object value)
        {
            SetPropertyValue(binder.Name, value);
            return true;
        }
        /// <summary>
        /// 動態物件動態方法呼叫時執行的實際程式碼
        /// </summary>
        /// <param name="binder"></param>
        /// <param name="args"></param>
        /// <param name="result"></param>
        /// <returns></returns>
        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 = 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.