检查对象是否更改的最佳做法是什么?

时间:2010-01-15 12:43:39

标签: c# .net

我需要知道如何检查对象是否已更改。基本上我需要类似于名为TrackChanges的属性,当我将其设置为true一次并且如果此对象中的任何数据被“更改”时,同一对象上的方法(IsObjectChanged)可以返回true。

你有没有需要这样的东西,你是如何解决的?如果已经有这种情况的最佳实践,我不想发明轮子?

我想在我的setter中调用TrackChange = true之前克隆该对象。当我调用IsObjectChanged()时,通过使用反射,我将比较它的所有公共字段值和克隆的副本。我不确定这是不是一个好方法。

有任何建议吗?

感谢, burak ozdogan

6 个答案:

答案 0 :(得分:16)

当我需要跟踪对象的属性更改以进行测试时,我在对象PropertyChanged事件上挂钩了一个事件处理程序。这对你有帮助吗?然后,您的测试可以根据更改执行他们想要的任何操作。通常我会计算更改次数,并将更改添加到词典等。

要实现此目的,您的课程必须实现INotifyPropertyChanged界面。然后任何人都可以附加和收听已更改的属性:

public class MyClass : INotifyPropertyChanged { ... }

[TestFixture]
public class MyTestClass
{
    private readonly Dictionary<string, int> _propertiesChanged = new Dictionary<string, int>();
    private int _eventCounter; 

    [Test]
    public void SomeTest()
    {
        // First attach to the object
        var myObj = new MyClass(); 
        myObj.PropertyChanged += SomeCustomEventHandler;
        myObj.DoSomething(); 
        // And here you can check whether the object updated properties - and which - 
        // dependent on what you do in SomeCustomEventHandler. 

        // E.g. that there are 2 changes - properties Id and Name changed once each: 
        Assert.AreEqual(2, _eventCounter); 
        Assert.AreEqual(1, _propertiesChanged["Id"]);
        Assert.AreEqual(1, _propertiesChanged["Name"]);
    }

    // In this example - counting total number of changes - and count pr property. 
    // Do whatever suits you. 
    private void SomeCustomEventHandler(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
        var property = e.PropertyName;
        if (_propertiesChanged.ContainsKey(property))
            _propertiesChanged[property]++;
        else
            _propertiesChanged[property] = 1;

        _eventCounter++;
    }
}

答案 1 :(得分:4)

这有两个部分。变更通知的事件是一个部分,但保持历史是另一个重要的部分。实体框架也是这样做的(就像LINQ to SQL一样),我也在自己的代码中实现了这一点。至少,您为成员保留一个标志,表明它已更改。根据您的要求,您也可以保留原始值。这通常成为单独对象的任务。实体框架将其更改跟踪保存在单独的对象中(如果我没记错的话,实体状态)。

在我自己的代码中,我开发了一个“DataMember”类,它不仅保存了值,还保留了更改标志,空状态和各种其他有用的东西。这些DataMembers是Entity类中的私有成员,Entity提供了将数据公开为简单数据类型的属性。属性get和set方法与DataMember交互以“做正确的事”,但DataMember确实改变了跟踪。我的Entity类继承自“EntityBase”类,它提供了在实体级别检查更改的方法,接受更改(重置更改标志)等。添加更改通知将是我接下来要做的事情,但是为个人提供DataMember类数据元素和拥有更改通知事件处理程序的EntityBase将简化这一过程。

编辑添加:

现在我正在工作,我可以添加一些代码示例。这是我的DataMember类的接口定义:

public interface IDataMember<T> : IDataMember
{
    T Value { get; set; }

    T Get();

    void Set(T value);
}

public interface IDataMember
{
    string FieldName { get; set; }
    string OracleName { get; set; }
    Type MemberType { get; }
    bool HasValue { get; set; }
    bool Changed { get; set; }
    bool NotNull { get; set; }
    bool PrimaryKey { get; set; }
    bool AutoIdentity { get; set; }
    EntityBase Entity { get; set;}

    object GetObjectValue();

    void SetNull();
}

这是实体类中的典型属性:

private DataMember<bool> m_Monday;

public bool? Monday
{
    get
    {
        if (m_Monday.HasValue)
            return m_Monday.Get();
        else
            return null;
    }
    set
    {
        if (value.HasValue)
            m_Monday.Set(value.Value);
        else
            m_Monday.SetNull();
    }
}

请注意,DataMember可以支持属性为可空或无。

添加DataMember的构造函数代码:

    m_Monday = new DataMember<bool>("Monday");
    Members.Add(m_Monday);

答案 2 :(得分:3)

布拉克,

您可以查看实体框架或Microsoft的其他框架。 您可以看到PropertyChanging或PropertyChanged等事件。

查看生成的代码。

您也可以查看NHibernate代码,但由于代码库非常庞大,因此最好查看Microsoft ORM生成器。

答案 3 :(得分:2)

实施并使用界面INotifyPropertyChanged。没有字符串文字的一种很酷的方法是here

答案 4 :(得分:1)

为什么不创建List并将第一个对象放入,然后可以通过简单比较将其与当前对象进行比较。

如上所述,您可以使用INotifyPropertyChanged查看对象中已更改的属性。

答案 5 :(得分:0)

您应该创建一个事件,并将其称为OnChanged

,而不是创建属性