程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 用C#創建一個混合型類

用C#創建一個混合型類

編輯:C#入門知識

.net 4.0添加了dynamic關鍵字。通過聲明dynamic變量,我們可以在C#這個靜態語言中使用一下動態語言的特性。微軟添加dynamic關鍵字,主要是為了使在C#中對COM編程更加簡化。對於我這個2003年才開始學編程的人來說COM就和匯編一樣,只有聽說過的份。那麼dynamic還有什麼其他的用途呢?


最近有點時間研究了一下,感覺很好玩,很Cool。作為學習成果,下面是一個通過IDynamicMetaObjectProvider實現的一個可以混合動態Property和靜態Property的類:

public class DynamicDomainObject : IDynamicMetaObjectProvider
    {
        private Dictionary _internalPropertyStorage;

        public DynamicDomainObject()
        {
            _internalPropertyStorage = new Dictionary();
        }

        public Object SetProperty(String key, Object value)
        {
            if (_internalPropertyStorage.ContainsKey(key))
            {
                _internalPropertyStorage[key] = value;
            }
            else
            {
                _internalPropertyStorage.Add(key, value);
            }
            return value;
        }

        public Object GetProperty(String key)
        {
            if (_internalPropertyStorage.ContainsKey(key))
            {
                return _internalPropertyStorage[key];
            }
            return null;
        }

        public void Dispose()
        {
            _internalPropertyStorage.Clear();
            _internalPropertyStorage = null;
        }

        public DynamicMetaObject GetMetaObject(Expression parameter)
        {
            return new DynamicDomainMetaObject(parameter, this, GetType());
        }

        private class DynamicDomainMetaObject : DynamicMetaObject
        {
            private Type _type;

            internal DynamicDomainMetaObject(
                Expression parameter, DynamicDomainObject value, Type type)
                : base(parameter, BindingRestrictions.Empty, value)
            {
                this._type = type;
            }

            public override DynamicMetaObject BindConvert(ConvertBinder binder)
            {
                var restrictions = BindingRestrictions.GetTypeRestriction(Expression, LimitType);

                if (binder.ReturnType.IsAssignableFrom(_type))
                    return new DynamicMetaObject(Expression.Constant(Value), restrictions);
                else
                    return new DynamicMetaObject(Expression.Default(binder.ReturnType), restrictions);
            }

            public override DynamicMetaObject BindGetMember(GetMemberBinder binder)
            {
                var restrictions = BindingRestrictions.GetTypeRestriction(Expression, LimitType);
                var propertyInfo = _type.GetProperties().FirstOrDefault(p => p.Name == binder.Name);

                var self = Expression.Convert(Expression, LimitType);

                Expression target;

                if (propertyInfo == null)
                {
                    target = Expression.Call(
                        self,
                        typeof(DynamicDomainObject).GetMethod("GetProperty"),
                        new Expression[] { Expression.Constant(binder.Name) }
                        );
                    target = FixReturnType(binder, target);
                }
                else
                {
                    target = Expression.Property(self, propertyInfo);
                    target = FixReturnType(binder, target);
                }

                return new DynamicMetaObject(target, restrictions);
            }

            public override DynamicMetaObject BindSetMember(SetMemberBinder binder, DynamicMetaObject value)
            {
                var propertyInfo = _type.GetProperties().FirstOrDefault(p => p.Name == binder.Name);

                var restrictions = BindingRestrictions.GetTypeRestriction(Expression, LimitType);
                var self = Expression.Convert(Expression, LimitType);

                Expression setCall;

                if (propertyInfo == null)
                {
                    var argument = Expression.Convert(value.Expression, typeof(Object));

                    setCall = Expression.Call(self, typeof(DynamicDomainObject).GetMethod("SetProperty"),
                                              new Expression[] { Expression.Constant(binder.Name), argument });
                }
                else
                {
                    var argument = Expression.Convert(value.Expression, propertyInfo.PropertyType);

                    setCall = Expression.Call(self, propertyInfo.GetSetMethod(),
                                              new Expression[] { argument });
                }

                return new DynamicMetaObject(Expression.Block(setCall, Expression.Default(binder.ReturnType)), restrictions);
            }

            private static Expression FixReturnType(DynamicMetaObjectBinder binder, Expression target)
            {
                if (target.Type != binder.ReturnType)
                {
                    if (target.Type == typeof(void))
                    {
                        target = Expression.Block(target, Expression.Default(binder.ReturnType));
                    }
                    else if (binder.ReturnType == typeof(void))
                    {
                        target = Expression.Block(target, Expression.Empty());
                    }
                    else
                    {
                        target = Expression.Convert(target, binder.ReturnType);
                    }
                }
                return target;
            }

            public override IEnumerable GetDynamicMemberNames()
            {
                return _type.GetProperties().Select(p => p.Name);
            }
        }
    }

在這個類中,我們通過一個Dictionary來存放動態訪問的Property,而當訪問靜態Property時,則直接訪問。在這個設計中,我沒有直接使用DynamicObject而是自己實現了IDynamicMetaObjectProvider,這樣做是因為在我們日常編程中,很多時候我們的類是需要繼承其他業務類的,對於C#和Java這種單繼承的語言來說,我們要盡量把父類留給業務需要。


如何使用這個類的例子,請參考這個類的測試代碼,按照慣例,我已將代碼發布到Github上了(https://github.com/mcai4gl2/dynamic-object)。至於在平常工作上這個類會有什麼用途,那就要看各位的需要了。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved