c#将class属性标记为脏

24 c# properties class

以下是定义对象状态的枚举的简单示例,以及显示此枚举的实现的类.

public enum StatusEnum
{
    Clean = 0,
    Dirty = 1,
    New = 2,
    Deleted = 3,
    Purged = 4
}


public class Example_Class
{
    private StatusEnum _Status = StatusEnum.New;

    private long _ID;
    private string _Name;

    public StatusEnum Status
    {
        get { return _Status; }
        set { _Status = value; }
    }

    public long ID
    {
        get { return _ID; }
        set { _ID = value; }
    }

    public string Name
    {
        get { return _Name; }
        set { _Name = value; }
    }
}
Run Code Online (Sandbox Code Playgroud)

当使用数据库中的数据填充类对象时,我们将枚举值设置为"clean".为了将大部分逻辑保留在表示层之外,如何在更改属性时将枚举值设置为"脏".

我正在思考一些事情;

public string Name
{
    get { return _Name; }
    set 
    {
        if (value != _Name)
        {
               _Name = value; 
           _Status = StatusEnum.Dirty;
        }
    }   
}
Run Code Online (Sandbox Code Playgroud)

在班级的每个属性的setter中.

这听起来像个好主意,有没有人对如何在表示层中分配脏标志有更好的想法.

Mar*_*ell 39

如果你真的想在类级别(或为此事,通知)一个肮脏的标志-你可以使用如下技巧来减少你的属性杂波(这里既展示IsDirtyPropertyChanged,只是为了好玩).

显然使用枚举方法是一件小事(我没有的唯一原因是保持示例简单):

class SomeType : INotifyPropertyChanged {
    private int foo;
    public int Foo {
        get { return foo; }
        set { SetField(ref foo, value, "Foo"); }
    }

    private string bar;
    public string Bar {
        get { return bar; }
        set { SetField(ref bar, value, "Bar"); }
    }

    public bool IsDirty { get; private set; }
    public event PropertyChangedEventHandler PropertyChanged;
    protected void SetField<T>(ref T field, T value, string propertyName) {
        if (!EqualityComparer<T>.Default.Equals(field, value)) {
            field = value;
            IsDirty = true;
            OnPropertyChanged(propertyName);
        }
    }
    protected virtual void OnPropertyChanged(string propertyName) {
        var handler = PropertyChanged;
        if (handler != null) {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

您也可以选择将其中的一部分推送到抽象基类中,但这是一个单独的讨论

  • +1:我在一些项目中使用完全相同(没有OnPropertyChanged,因为我不关心它)作为在每个属性中进行相等性检查的改进.绝对值得一试. (2认同)
  • 我假设你有一些额外的方法在初始加载后将IsDirty设置为false?就目前而言,即使在第一次设置属性后,IsDirty也会成立. (2认同)

Jon*_*eet 23

一种选择是在写入时改变它; 另一种方法是保留所有原始值的副本,并在有人要求时计算肮脏.这样做的另一个好处是,您可以准确地确定哪些字段已更改(以及以何种方式),这意味着您可以发布最小更新语句并使合并冲突解决方案更容易一些.

您还可以将所有肮脏检查放在一个地方,这样就不会污染您的其余代码.

我并不是说这是完美的,但这是一个值得考虑的选择.

  • +1我过去实现了这一点,我最终讨厌它.这是一场维护噩梦.DirtyFlag应该成为反模式恕我直言.如果实现此功能,则会丢失自动属性,并且您的代码会大量增加 (9认同)
  • @RaheelKhan:听起来这作为答案发布比评论更好。 (2认同)

Fre*_*els 16

如果要以这种方式实现它,并且希望减少代码量,可以考虑应用面向方面编程.

例如,您可以使用像PostSharp这样的编译时编织器,并创建可应用于属性的"方面".然后,此方面确保在适当时设置脏标志.

方面可以如下所示:

[Serializable]
[AttributeUsage(AttributeTargets.Property)]
public class ChangeTrackingAttribute : OnMethodInvocationAspect
{
    public override void OnInvocation( MethodInvocationEventArgs e )
    {
        if( e.Delegate.Method.ReturnParameter.ParameterType == typeof(void) )
        {
              // we're in the setter
              IChangeTrackable target = e.Delegate.Target as IChangeTrackable;

              // Implement some logic to retrieve the current value of 
              // the property
              if( currentValue != e.GetArgumentArray()[0] )
              {
                  target.Status = Status.Dirty;
              }
              base.OnInvocation (e);
        } 
    }  
} 
Run Code Online (Sandbox Code Playgroud)

Offcourse,这意味着你想要实现ChangeTracking的类应该实现IChangeTrackable至少具有'Status'属性的接口(自定义接口).

您还可以创建自定义属性ChangeTrackingProperty,并确保上面创建的方面仅应用于使用此ChangeTrackingProperty属性修饰的属性.

例如:

public class Customer : IChangeTrackable
{
    public DirtyState Status
    {
        get; set;
    }

    [ChangeTrackingProperty]
    public string Name
    { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

这是我看到它的一点点.您甚至可以确保PostSharp在编译时检查具有使用ChangeTrackingProperty属性修饰的属性的类是否实现了IChangeTrackable接口.