你的位置:首页 > ASP.net教程

[ASP.net教程]Lind.DDD~实体属性变更追踪器的实现


回到目录

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

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

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

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

  /// <summary>  /// 领域模型,实体模型基类,它可能有多种持久化方式,如DB,File,Redis,Mongodb,/// 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>    [3), 3), DisplayName("建立时间"), Column("CreateTime"), Required]    public DateTime CreateDateTime { get; set; }    /// <summary>    /// 更新时间    /// </summary>    [2), 2), DisplayName("更新时间"), Column("UpdateTime"), Required]    public DateTime UpdateDateTime { get; set; }    /// <summary>    /// 实体状态    /// </summary>    [1), 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;

回到目录