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

C# 检查对象是否已更改的最佳做法是什么?,c#,.net,C#,.net,我需要知道如何检查对象是否已更改。基本上,我需要一个名为TrackChanges的属性,当我将其设置为true时,如果此对象中的任何数据被“更改”,则同一对象(IsObjectChanged)上的方法可以返回true 你曾经需要过这样的事情吗?你是如何解决的?我不想发明轮子,如果已经有这样一个场景的最佳实践 我想在调用TrackChange=true之前,在其setter中克隆该对象。当我使用反射调用IsObjectChanged()时,我会将它的所有公共字段值与克隆副本进行比较。我不确定这是不

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

你曾经需要过这样的事情吗?你是如何解决的?我不想发明轮子,如果已经有这样一个场景的最佳实践

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

有什么建议吗

谢谢,
burak ozdogan

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

要实现这一点,类必须实现接口。然后,任何人都可以附加和侦听更改的属性:

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++;
    }
}
公共类MyClass:INotifyPropertyChanged{…}
[测试夹具]
公共类MyTestClass
{
私有只读词典_propertiesChanged=新词典();
私人int_事件计数器;
[测试]
公共测试()
{
//首先附加到对象
var myObj=new MyClass();
myObj.PropertyChanged+=SomeCustomEventHandler;
myObj.DoSomething();
//在这里,您可以检查对象是否更新了属性,以及
//取决于您在SomeCustomEventHandler中执行的操作。
//例如,有两个更改-属性Id和名称每更改一次:
断言.AreEqual(2,_eventCounter);
Assert.AreEqual(1,_propertiesChanged[“Id”]);
Assert.AreEqual(1,_propertiesChanged[“Name”]);
}
//在本例中-计数更改总数-和计数pr属性。
//做任何适合你的事。
私有void SomeCustomEventHandler(对象发送方,System.ComponentModel.PropertyChangedEventArgs e)
{
var property=e.PropertyName;
如果(_propertiesChanged.ContainsKey(property))
_属性更改[属性]+;
其他的
_属性更改[属性]=1;
_eventCounter++;
}
}
Burak

您可以看看实体框架或Microsoft的其他框架。 您可以看到类似PropertyChanged或PropertyChanged的事件

看看生成的代码


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

与其创建属性,不如创建一个事件,并将其称为类似于
OnChanged

的内容,为什么不创建一个列表并放入第一个对象,然后,您可以使用简单的比较将其与当前对象进行比较


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

实现并使用该接口。不使用字符串文字的一种很酷的方法是。

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

在我自己的代码中,我开发了一个“DataMember”类,它不仅保存值,还保存更改标志、空状态和其他各种有用的东西。这些DataMember是实体类中的私有成员,实体提供了将数据公开为简单数据类型的属性。属性get和set方法与DataMember交互以“做正确的事情”,但DataMember确实更改了跟踪。我的实体类继承自一个“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();
}
公共接口IDataMember:IDataMember
{
T值{get;set;}
T Get();
无效集(T值);
}
公共接口IDatamber
{
字符串字段名{get;set;}
字符串OracleName{get;set;}
类型MemberType{get;}
bool HasValue{get;set;}
bool已更改{get;set;}
bool NotNull{get;set;}
布尔主密钥{get;set;}
布尔自动标识{get;set;}
EntityBase实体{get;set;}
对象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();
    }
}
私人数据成员m_周一;
公共场所?星期一
{
得到
{
如果(m_周一,HasValue)
周一返回m_。获取();
其他的
返回null;
}
设置
{
if(value.HasValue)
m_Monday.Set(value.value);
其他的
m_Monday.SetNull();
}
}
请注意,DataMember可以支持属性为null,也可以不支持

用于添加DataMember的构造函数代码:

    m_Monday = new DataMember<bool>("Monday");
    Members.Add(m_Monday);
m_Monday=新数据成员(“星期一”);
成员.增补(星期一);
不错!Bur问题:1)什么被认为是“更改?”在msdn中,它说它是在调用setter时抛出的。所以我仍然需要检查它是否不同