回到目录

看着这个标题很复杂,大叔把它拆开说一下,实体属性-变更-追踪器,把它拆成三部分大家看起来就容易懂一些了,实体属性:领域实体里有自己的属性,属性有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 = ), XmlElement(Order = ), DisplayName("建立时间"), Column("CreateTime"), Required]
public DateTime CreateDateTime { get; set; }
/// <summary>
/// 更新时间
/// </summary>
[XmlIgnore, DataMember(Order = ), XmlElement(Order = ), DisplayName("更新时间"), Column("UpdateTime"), Required]
public DateTime UpdateDateTime { get; set; }
/// <summary>
/// 实体状态
/// </summary>
[XmlIgnore, DataMember(Order = ), XmlElement(Order = ), 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 == )
{
string propertyName = Regex.Split(callMsg.MethodName, "set_")[];
//这里检测到是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 = ;

aaarticlea/png;base64,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" alt="" />

回到目录

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

  1. Lind.DDD敏捷领域驱动框架~介绍

    回到占占推荐博客索引 最近觉得自己的框架过于复杂,在实现开发使用中有些不爽,自己的朋友们也经常和我说,框架太麻烦了,要引用的类库太多:之前架构之所以这样设计,完全出于对职责分离和代码附复用的考虑,主要 ...

  2. Lind.DDD.Aspects通过Plugins实现方法的动态拦截~Lind里的AOP

    回到目录 .Net MVC之所以发展的如些之好,一个很重要原因就是它公开了一组AOP的过滤器,即使用这些过滤器可以方便的拦截controller里的action,并注入我们自己的代码逻辑,向全局的异常 ...

  3. Lind.DDD.Domain.IOwnerBehavor对实体的意义

    回到目录 对于Lind.DDD架构,我之前写了不少文章,对于它的Domain模式也介绍了不少,像之前的IEntity,ILogicDeleteBehavor,IModifyBehavor,IStatu ...

  4. Lind.DDD.Domain领域模型介绍

    回到目录 Lind.DDD.Domain位于Lind.DDD核心项目中,它主要面向领域实体而设计,由一个IEntity的标识接口,EntityBase基类和N个Entity实体类组成,其中IEntit ...

  5. Lind.DDD敏捷领域驱动框架~Lind.DDD各层介绍

    回到目录 Lind.DDD项目主要面向敏捷,快速开发,领域驱动等,对于它的分层也是能合并的合并,比之前大叔的框架分层更粗糙一些,或者说更大胆一些,在开发人员使用上,可能会感觉更方便了,更益使用了,这就 ...

  6. Lind.DDD.ConfigConstants统一管理系统配置

    回到目录 Lind.DDD.ConfigConstants属于新添加的组件,用来帮助我们安全的进行配置消息的管理,我们在开发项目时,有个感觉,你的config配置项会越来越多,越来越难以阅读,随着你引 ...

  7. Lind.DDD.Repositories.Mongo层介绍

    回到目录 之前已经发生了 大叔之前讲过被仓储化了的Mongodb,而在大叔开发了Lind.DDD之后,决定把这个东西再搬到本框架的仓储层来,这也是大势所趋的,毕竟mongodb是最像关系数据库的NoS ...

  8. Lind.DDD.UoW工作单元的实现

    回到目录 工作单元UoW我们几乎在任务一个像样的框架里都可以找到它的足迹,是的,对于大型系统来说,他是很重要的,保持数据一致性,维持事务状态这都是它要为系统实现的功能,而在不同的框架里,实现UoW的机 ...

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

    回到目录 戏说当年 大叔原创的分布式数据集缓存在之前的企业级框架里介绍过,大家可以关注<我心中的核心组件(可插拔的AOP)~第二回 缓存拦截器>,而今天主要对Lind.DDD.Cachin ...

随机推荐

  1. Android开发学习之路-图片颜色获取器开发(1)

    系列第一篇,从简单的开始,一步一步完成这个小项目. 颜色获取就是通过分析图片中的每个像素的颜色,来分析整个图片的主调颜色,有了主调颜色,我们可以用于图片所在卡片的背景或者标题颜色,这样整体感更加强烈. ...

  2. Atitit 索引技术--位图索引

    Atitit 索引技术--位图索引 索引在数据结构上可以分为三种B树索引.位图索引和散列索引 存储原理 编辑 位图索引对数据表的列的每一个键值分别存储为一个位图,Oracle对于不同的版本,不同的操作 ...

  3. 【转载】如何自学深度学习技术,大神Yann LeCun亲授建议

    编者按:Quora 上有网友提问:自学机器学习技术,你有哪些建议?(What are your recommendations for self-studying machine learning), ...

  4. MongoDB replica set IDs do not match

    在搭建MongoDB(版本 3.2.9)的Replica Set时,使用 rs.status() 查看Replica Set的状态,发现一个成员异常:replica set IDs do not ma ...

  5. Package Configurations的使用示例

    SSIS提供Package Configurations功能,能够动态修改配置数据,使package执行不同的变量,从不同的connection中获取数据,而这些变化,不需要修改Package,不需要 ...

  6. 将 instance 连接到 second_local_net - 每天5分钟玩转 OpenStack(85)

    今天是 local network 的最后一个小节,我们将验证两个local network 的连通性. launch 新的 instance “cirros-vm3”,网络选择 second_loc ...

  7. scikit-learn 支持向量机算法库使用小结

    之前通过一个系列对支持向量机(以下简称SVM)算法的原理做了一个总结,本文从实践的角度对scikit-learn SVM算法库的使用做一个小结.scikit-learn SVM算法库封装了libsvm ...

  8. OWIN 中 K Commands(OwinHost.exe)与 Microsoft.AspNet.Hosting 的角色问题

    问题详情:K Commands(OwinHost.exe)是不是 OWIN 中的 Host 角色?如果是,那 Microsoft.AspNet.Hosting 对应的是 OWIN 中的哪个角色? OW ...

  9. 深入seajs源码系列二

    模块类和状态类 参照上文的demo,我们结合源码分析在简单的API调用的背后,到底使用了什么技巧来实现各个模块的依赖加载以及模块API的导出. 首先定义了一个Module类,对应与一个模块 funct ...

  10. StructureMap.dll 中的 GetInstance 重载 + 如何利用 反射动态创建泛型类

    public static T GetInstance<T>(ExplicitArguments args); // // Summary: // Creates a new instan ...