zoukankan      html  css  js  c++  java
  • Lind.DDD~实体属性变更追踪器的实现

    回到目录

    看着这个标题很复杂,大叔把它拆开说一下,实体属性-变更-追踪器,把它拆成三部分大家看起来就容易懂一些了,实体属性:领域实体里有自己的属性,属性有getter,setter块,用来返回和设置属性的内容;变更:当前属性为赋值时,我们对它进行监视;追踪器:对变量的内容进行处理。好了,我们回到Lind.DDD框架中,在框架里有领域实体基类EntityBase,这个类是所有实体的基类,它公开了一些属性和方法,我们对这个基类进行一些设置,让所有子类都继承它,享用它。

    1 属性变更追踪接口和它的事件

        // 摘要:
        //     向客户端发出某一属性值已更改的通知。
        public interface INotifyPropertyChanged
        {
            // 摘要:
            //     在更改属性值时发生。
            event PropertyChangedEventHandler PropertyChanged;
        }

    2 基类EntityBase,添加了事件和它的方法,及触发事件的方法

        /// <summary>
        /// 领域模型,实体模型基类,它可能有多种持久化方式,如DB,File,Redis,Mongodb,XML等
        /// Lind.DDD框架的领域模型与数据库实体合二为一
        /// </summary>
        [PropertyChangedAttribute]
        public abstract class EntityBase : ContextBoundObject, IEntity, INotifyPropertyChanged
        {
            /// <summary>
            /// 实体初始化
            /// </summary>
            public EntityBase()
            {
                this.Status = Status.Normal;
                this.UpdateDateTime = DateTime.Now;
                this.CreateDateTime = DateTime.Now;
                this.PropertyChanged += EntityBase_PropertyChanged;
            }
    
            /// <summary>
            /// 建立时间
            /// </summary>
            [XmlIgnore, DataMember(Order = 3), XmlElement(Order = 3), DisplayName("建立时间"), Column("CreateTime"), Required]
            public DateTime CreateDateTime { get; set; }
            /// <summary>
            /// 更新时间
            /// </summary>
            [XmlIgnore, DataMember(Order = 2), XmlElement(Order = 2), DisplayName("更新时间"), Column("UpdateTime"), Required]
            public DateTime UpdateDateTime { get; set; }
            /// <summary>
            /// 实体状态
            /// </summary>
            [XmlIgnore, DataMember(Order = 1), XmlElement(Order = 1), DisplayName("状态"), Required]
            public Status Status { get; set; }
    
            /// <summary>
            /// 拿到实体验证的结果列表
            /// 结果为null或者Enumerable.Count()==0表达验证成功
            /// </summary>
            /// <returns></returns>
            public IEnumerable<RuleViolation> GetRuleViolations()
            {
                var properties = this.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance).ToArray();
    
                foreach (var i in properties)
                {
                    var attr = i.GetCustomAttributes();
                    foreach (var a in attr)
                    {
                        var val = (a as ValidationAttribute);
                        if (val != null)
                            if (!val.IsValid(i.GetValue(this)))
                            {
                                yield return new RuleViolation(val.ErrorMessage, i.Name);
                            }
                    }
                }
    
            }
    
            #region PropertyChangedEventHandler Events
            /// <summary>
            /// 属性值变更事件
            /// </summary>
            public event PropertyChangedEventHandler PropertyChanged;
            /// <summary>
            /// 事件实例
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            void EntityBase_PropertyChanged(object sender, PropertyChangedEventArgs e)
            {
                Console.WriteLine("属性:{0},值:{1}", e.PropertyName, sender.GetType().GetProperty(e.PropertyName).GetValue(sender));
            }
            /// <summary>
            /// 触发事件,写在每个属性的set块中CallerMemberName特性表示当前块的属性名
            /// </summary>
            /// <param name="propertyName"></param>
            public void OnPropertyChanged([CallerMemberName] string propertyName = null)
            {
                if (PropertyChanged != null)
                    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
    
            #endregion
    
        }

    3 定义变更拦截器特性

        /// <summary>
        /// 类中方法拦截的特性
        /// </summary>
        public class PropertyChangedAttribute : ProxyAttribute
        {
            public override MarshalByRefObject CreateInstance(Type serverType)
            {
                PropertyChangedProxy realProxy = new PropertyChangedProxy(serverType);
                return realProxy.GetTransparentProxy() as MarshalByRefObject;
            }
        }

    4 实现拦截器功能

        /// <summary>
        /// 属性变更拦截器
        /// </summary>
        public class PropertyChangedProxy : RealProxy
        {
            Type serverType;
            public PropertyChangedProxy(Type serverType)
                : base(serverType)
            {
                this.serverType = serverType;
            }
            public override IMessage Invoke(IMessage msg)
            {
                //构造方法
                if (msg is IConstructionCallMessage)
                {
                    IConstructionCallMessage constructCallMsg = msg as IConstructionCallMessage;
                    IConstructionReturnMessage constructionReturnMessage = this.InitializeServerObject((IConstructionCallMessage)msg);
                    RealProxy.SetStubData(this, constructionReturnMessage.ReturnValue);
                    return constructionReturnMessage;
                }
                //其它方法(属性也是方法,它会被翻译成set_property,get_property,类似于java里的属性封装)
                else if (msg is IMethodCallMessage)
                {
    
                    IMethodCallMessage callMsg = msg as IMethodCallMessage;
                    object[] args = callMsg.Args;
                    IMessage message;
                    try
                    {
    
                        if (callMsg.MethodName.StartsWith("set_") && args.Length == 1)
                        {
                            string propertyName = Regex.Split(callMsg.MethodName, "set_")[1];
                            //这里检测到是set方法,然后应怎么调用对象的其它方法呢?
                            var method = this.serverType.GetMethod("OnPropertyChanged");
                            if (method != null)
                            {
                                var obj = GetUnwrappedServer();
                                obj.GetType().GetProperty(propertyName).SetValue(obj, args.FirstOrDefault());
                                method.Invoke(obj, new object[] { propertyName });//这块对象为空了
                            }
    
                        }
    
                        object o = callMsg.MethodBase.Invoke(GetUnwrappedServer(), args);
                        message = new ReturnMessage(o, args, args.Length, callMsg.LogicalCallContext, callMsg);
                    }
    
                    catch (Exception e)
                    {
    
                        message = new ReturnMessage(e, callMsg);
    
                    }
    
                    return message;
    
                }
    
                return msg;
    
            }
        }

    5 总结

    本例子主要让大家了解了事件,事件触发机制,AOP拦截技术等知识点,而且通过本例子,我们可以对类的属性进行监视,并订阅一些方法来处理这些变更行为!下面这个代码是最简单的属性变更的记录,本user对象为赋值时,它的两个被set的属性成为了监视的对象

         User u1 = new User();
         u1.UserName = "OK";
         u1.Age = 100;

    回到目录

  • 相关阅读:
    DevExpress控件经验集合
    Oracle 11g基础
    NoSuchMethodException问题总结
    设计模式学习笔记十四:适配器模式
    设计模式学习笔记十三:模板方法模式
    设计模式学习笔记十二:访问者模式
    设计模式学习笔记十一:观察者模式
    【亲述】Uber容错设计与多机房容灾方案
    Linux 动态监听进程shell
    玩具:加减法验证码(1+?=4)
  • 原文地址:https://www.cnblogs.com/lori/p/5025964.html
Copyright © 2011-2022 走看看