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;

本文转自博客园张占岭(仓储大叔)的博客,原文链接:Lind.DDD~实体属性变更追踪器的实现,如需转载请自行联系原博主。

时间: 2024-07-30 07:01:28

Lind.DDD~实体属性变更追踪器的实现的相关文章

Lind.DDD.Caching分布式数据集缓存介绍

戏说当年 大叔原创的分布式数据集缓存在之前的企业级框架里介绍过,大家可以关注<我心中的核心组件(可插拔的AOP)~第二回 缓存拦截器>,而今天主要对Lind.DDD.Caching进行更全面的解决,设计思想和主要核心内容进行讲解.其实在很多缓存架构在业界有很多,向.net运行时里也有Cache,也可以实现简单的数据缓存的功能,向前几年页面的静态化比较流行,就出现了很多Http的"拦截器",对当前HTTP响应的内容进行完整的页面缓存,缓存的文件大多数存储到磁盘里,访问的时间直

接口式实体定义之——自定义实体属性+实体多根继承

最新版本的NBear中除了本文中提到的两个功能之外,还包括如下内容: 1)支持EntityFactory.CreateObject和CreateObjectList现在支持基于DataSet或IDataReader中的字段名称而不仅仅是原来的基于字段顺序的数据填充了: 2)Gateway.Save和Insert方法现在支持自动返回新插入的纪录的自增长ID字段了(当然,前提是,这个实体对应的表确实使用自增长主键字段). 自定义实体属性 什么是CustomProperty呢? CustomPrope

zf框架的数据库追踪器使用示例

 这篇文章主要介绍了zf框架的数据库追踪器使用示例,现把追踪器的使用方法分享给大家,需要的朋友可以参考下 调用追踪器的方法    代码如下: $Profiler = $Db -> getProfiler();    代码如下: <?php /* 追踪器的使用方法 */   //引入Loader类(自动加载类) require_once("Zend/Loader.php"); //使用Loader类引入一个Db类 Zend_Loader::loadClass("Ze

Linq之隐式类型、自动属性、初始化器、匿名类

目录 写在前面 系列文章 隐式类型 自动属性 初始化器 匿名类 总结 写在前面 上篇文章是本系列的小插曲,也是在项目中遇到,觉得有必要总结一下,就顺手写在了博客中,也希望能帮到一些朋友.本文将继续介绍linq系列的基础知识,隐式类型,自动属性,初始化器,匿名类的相关概念,这些内容也许与linq相关也许不相关,但还是放一起总结吧,也算是复习了.部分内容通过反编译的方式一探究竟. 系列文章 Linq之Lambda表达式初步认识 Linq之Lambda进阶 隐式类型 先看看Msdn上对隐式类型的简单定

无法显式调用运算符或访问器 无法对属性或索引器赋值

问题描述 无法显式调用运算符或访问器 无法对属性或索引器赋值 困扰了好久了.c#反汇编回来的程序报了2个错误, this.msc.add_Error(new DScriptControlSource_ErrorEventHandler(OnError)); this.msc.add_Timeout(new DScriptControlSource_TimeoutEventHandler(OnTimeout)); 提示:"MSScriptControl.DScriptControlSource_E

问题-错误 1 无法对属性或索引器“AnonymousType#1.EmployeeId”赋值 -- 它是只读的

问题描述 错误 1 无法对属性或索引器"AnonymousType#1.EmployeeId"赋值 -- 它是只读的 var temp = db.UseVihicle.Where(x => x.Id == Id).Select(a => new { a.EmployeeId, a.VihicleId, a.StartTime, a.EndTime, a.Description, a.Destination, a.Cause, a.Status }); foreach (va

app-对于Endomondo运动追踪器,具体实现应用了Android里的哪些技术。求大神指点。

问题描述 对于Endomondo运动追踪器,具体实现应用了Android里的哪些技术.求大神指点. 现在在写毕业论文的开题报告,类似于运动追踪器的,但是对于这个APP总体上还是没有理解.对于这类APP包含了哪几方面的技术.求各路大神指点一下.

反射 索引器-C#反射获取属性排除索引器

问题描述 C#反射获取属性排除索引器 C#GetType().GetProperties()获取所有属性时,包括了索引器,如果排除掉索引器,BindingFlags可以筛选但不知道是哪个? 解决方案 if (pi.GetIndexParameters().Length > 0) 说明这个是索引器

zf框架的数据库追踪器使用示例_php实例

调用追踪器的方法 复制代码 代码如下: $Profiler = $Db -> getProfiler(); 复制代码 代码如下: <?php/*追踪器的使用方法*/ //引入Loader类(自动加载类)require_once("Zend/Loader.php");//使用Loader类引入一个Db类Zend_Loader::loadClass("Zend_Db");//引入Zend_Db的状态器Zend_Loader::loadClass("