通过Castle的DynamicProxy处理PropertyChanging / PropertyChanged

时间:2011-12-20 18:40:33

标签: c# .net inotifypropertychanged castle

我目前有一个setter方法,如下所示:

 private string _a;
    public virtual string A
    {
        get { return _a; }
        set
        {
            if (_a!= value)
            {
                if (this.OnPropertyChanging("A", _a, value))
                {
                    var previousValue = _a;
                    _a = value;
                    this.OnPropertyChanged("A", previousValue, value);
                }
            }

        }
    }

我已经在Wily博士的Apprentice(http://stackoverflow.com/a/8578507/981225)的帮助下实现了这一功能,其中包含一个自定义的更改处理程序,可以跟踪旧的和当前的值,以及将Changing事件设置为'Canceled',这样就不会发生PropertyChange。

这完美无缺。但是,我们有数百个属性,这是重复的很多代码。

我过去使用过Castle的DynamicProxy,以避免写'OnPropertyChanged(“A”)'。

如何在此setter中实现逻辑,作为Proxy的Intercept方法的一部分?可能吗?谢谢。

1 个答案:

答案 0 :(得分:1)

也许我有点迟了,但我在Linq-To-SharePoint模型中遇到了类似的任务。如果有人还在想,我会勾勒出一些代码。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Castle.DynamicProxy;
using System.Reflection;
using System.ComponentModel;


namespace DemoSpace
{
    public abstract class EntityBase : INotifyPropertyChanged, INotifyPropertyChanging
    {
        public virtual void OnPropertyChanging(string propertyName, object value)
        {
            if ((null != PropertyChanging))
            {
                PropertyChanging(this, new PropertyChangingEventArgs(propertyName));
            }
        }

        public virtual void OnPropertyChanged(string propertyName)
        {
            if ((null != PropertyChanged))
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        public event PropertyChangedEventHandler  PropertyChanged;

        public event PropertyChangingEventHandler  PropertyChanging;
    }

    public class DemoInterceptor<T> : IInterceptor where T : EntityBase
    {
        private T _target;

        public DemoInterceptor(T target)
        {
            _target = target;
        }

        public void Intercept(IInvocation invocation)
        {
            if (invocation.Method.IsPublic && invocation.Method.Name.StartsWith("set_"))
            {
                string propertyName = invocation.Method.Name.Substring(4);
                string privateFieldName = ResolvePropName(propertyName); 


                object original_value = 
                    typeof(T).GetField(privateFieldName, BindingFlags.NonPublic | BindingFlags.Instance).GetValue(_target);

                _target.OnPropertyChanging(propertyName, original_value);
                invocation.Method.Invoke(_target, invocation.Arguments);
                _target.OnPropertyChanged(propertyName);

            }
            else
            {
                invocation.ReturnValue = invocation.Method.Invoke(_target, invocation.Arguments);
            }

        }

        public virtual string ResolvePropName(string propertyName)
        {
            return "_" + propertyName.Substring(0, 1).ToLower() + propertyName.Substring(1);
        }

    }
}