(是否存在)检查(复杂)pocomodel中的属性是否已更改的简单方法?

时间:2012-10-26 14:18:17

标签: c#

我想知道是否有一种简单的方法可以检查房产是否已经改变。就像下面的层次结构,当Child.Name更改(isDirty)时,我想知道。

GrantParent
- Parent
-- Child

在我目前的情况下,我需要浏览模型以查看是否有任何变化。

ps:我正在使用IChangeTracking

一直在考虑缓存序列化对象的哈希值。 (太慢了?)

或创建更改请求,调用父项直到达到grantparent。 (健谈的?)

  public class Parent: BaseEntity
  {
    private Child _child;
    public Child Child
    {
      get { return _child; }
      set { _child = value; OnPropertyChanged("Child"); }
    }
  }

  public class Child : BaseEntity
  {
    private  int _id;
    public int Id {
      get { return _id; }
      set { _id = value; OnPropertyChanged("Id"); }
    }
  }



 [DataContract]
  [Serializable]
  public abstract class BaseEntity : INotifyPropertyChanged
  {
    protected BaseEntity()
    {
      PropertyChanged += PropertyChangedEventHandler;
    }

    private void PropertyChangedEventHandler(object sender, PropertyChangedEventArgs e)
    {
      if (e != null && !String.Equals(e.PropertyName, "IsChanged", StringComparison.Ordinal))
      {
        this.IsChanged = true;
      }
    }

    protected void OnPropertyChanged<T>(Expression<Func<T>> property)
    {
      MemberExpression me = property.Body as MemberExpression;
      if (me == null || me.Expression != property.Parameters[0]
            || me.Member.MemberType != MemberTypes.Property)
      {
        throw new InvalidOperationException(
            "Now tell me about the property");
      }
      var handler = PropertyChanged;
      if (handler != null) handler(this,
        new PropertyChangedEventArgs(me.Member.Name));
    }

    [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public bool IsChanged
    {
      get
      {
        lock (_notifyingObjectIsChangedSyncRoot)
        {
          return _notifyingObjectIsChanged;
        }
      }

      protected set
      {
        lock (_notifyingObjectIsChangedSyncRoot)
        {
          if (!Boolean.Equals(_notifyingObjectIsChanged, value))
          {
            _notifyingObjectIsChanged = value;

            if (IsDirtyChanged != null)
              IsDirtyChanged();

            this.OnPropertyChanged("IsChanged");
          }
        }
      }
    }

    private bool _notifyingObjectIsChanged;
    private readonly object _notifyingObjectIsChangedSyncRoot = new Object();

    public void AcceptChanges()
    {
      this.IsChanged = false;
    }
  }

最后我使用了我已经使用的XML序列化程序的XML模型的比较。我没有做过&#39;需要&#39;每秒一次(或左右)即时变化检测就足够了。现在我用自上次保存以来的XML模型检查XML模型。

2 个答案:

答案 0 :(得分:3)

您需要让每个属性自己跟踪它,并存储一些信息,指出哪些属性已更改,或者可能在项目更改时触发事件。

基本上每个属性都具有与此类似的逻辑:

public class MyClass : INotifyPropertyChanged
{
    private int _value;
    public int Value
    {
        get
        {
            return _value;
        }
        set
        {
            _value = value;
            PropertyChanged(this, new PropertyChangedEventArgs("Value"));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

这将允许您向PropertyChanged事件添加事件处理程序,以便在更改属性时触发代码。

答案 1 :(得分:1)

我最近参与了一个项目,我们让所有节点/叶子都实现了node.Modified属性,并使用INotifyPropertyChanged来提升node.Modified的状态变化。然后所有的父母订阅了他们孩子的财产变更,如果node.Modified被设置为真,那么他们将自己的node.Modified设置为真。

就像你说的那样,它有点健谈,但由于我们每秒钟都没有看到成千上万的变化而且我们的层次结构只有3个级别,但它还没有成为我们的性能瓶颈深。

这是一个快速示例:

class Node : INotifyPropertyChanged
{

    public Node()
    {
        Children = new List<Node>();
    }
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string name)
    {
        var temp = PropertyChanged;
        if (temp != null)
            temp(this, new PropertyChangedEventArgs(name));
    }

    public IList<Node> Children { get; private set; }
    public void AddChild(Node node)
    {
        node.PropertyChanged += ChildPropertyChanged;
        Children.Add(node);
    }

    void ChildPropertyChanged(object sender, PropertyChangedEventArgs args)
    {
        if (args.PropertyName == "Modified")
            Modified |= ((Node)sender).Modified;
    }

    bool _modified = false; 
    public bool Modified 
    {
        get { return _modified; } 
        set 
        {
            if (_modified != value)
            {
                _modified = value;
                OnPropertyChanged("Modified");
            }

        } 
    }
编辑:使用某种消息总线还有另一种方法。它可能不完美,但它是解决问题的另一种方法,所以我也会分享它。我很快就破解了一个简单的Msg总线...

static class Bus<T>
{

    public static Dictionary<object, Action<object, T>> Subscriptions = new Dictionary<object, Action<object, T>>();
    public static void Raise(object sender, T message)
    {
        foreach (Action<object, T> action in Subscriptions.Values)
        {
            action(sender, message);
        }
    }

    public static void Subscribe(object subscriber, Action<object, T> action)
    {
        Subscriptions[subscriber] = action;
    }

    public static void Unsubscribe(object subscriber)
    {
        if (Subscriptions.ContainsKey(subscriber))
            Subscriptions.Remove(subscriber);
    }

}

public class WasModified { }

修改后的Node

class Node
{

    public Node()
    {
        Children = new List<Node>();
    }

    public IList<Node> Children { get; private set; }

    bool _modified = false; 
    public bool Modified 
    {
        get { return _modified; } 
        set 
        {
            if (_modified != value)
            {
                _modified = value;

                if (_modified == true)
                    Bus<WasModified>.Raise(this, new WasModified());
            }

        } 
    }
}

最后,它的使用。

    static void Main(string[] args)
    {

        Node parent = new Node();
        Bus<WasModified>.Subscribe(parent, (s,a)=> parent.Modified = true);
        Node child = new Node();
        Node gchild = new Node();
        parent.Children.Add(child);
        parent.Children.Add(gchild);
        gchild.Modified = true;
        Console.WriteLine(parent.Modified);


        Console.ReadLine();
    }

消息总线不需要冒泡到父对象,并且每次想要查看修改后的内容时都不需要递归到它们中,所以也许它就是你的&# #39;重新寻找。