16

この行の内部動作に関する私の理解が正しい場合:

public int MyInt { get; set; }

次に、舞台裏でこれを行います。

private int _MyInt { get; set; }
Public int MyInt {
    get{return _MyInt;}
    set{_MyInt = value;}
}

私が本当に必要なのは:

private bool IsDirty { get; set; }

private int _MyInt { get; set; }
Public int MyInt {
    get{return _MyInt;}
    set{_MyInt = value; IsDirty = true;}
}

しかし、私はそれを次のように書きたいと思います:

private bool IsDirty { get; set; }

public int MyInt { get; set{this = value; IsDirty = true;} }

これは機能しません。問題は、IsDirty を実行する必要があるオブジェクトのいくつかには多数のプロパティがあり、自動ゲッター/セッターを使用する方法があることを望んでいますが、フィールドが変更されたときに IsDirty を設定します。

これは可能ですか、それとも自分のクラスのコード量を 3 倍にすることを諦めなければなりませんか?

4

5 に答える 5

25

これは自分で処理する必要があります。

private bool IsDirty { get; set; }

private int _myInt; // Doesn't need to be a property
Public int MyInt {
    get{return _myInt;}
    set{_myInt = value; IsDirty = true;}
}

自動プロパティ メカニズムを使用しながら、カスタム ロジックをセッターに追加する構文はありません。独自のバッキング フィールドを使用してこれを記述する必要があります。

これはよくある問題です。たとえば、INotifyPropertyChanged.

于 2011-02-15T21:40:44.403 に答える
11

isDirty フラグ機能を必要とする一部のプロパティをラップする IsDirty デコレータ (デザイン パターン) を作成します。

public class IsDirtyDecorator<T>
{
    public bool IsDirty { get; private set; }

    private T _myValue;
    public T Value
    {
        get { return _myValue; }
        set { _myValue = value; IsDirty = true; }
    }
}

public class MyClass
{
    private IsDirtyDecorator<int> MyInt = new IsDirtyDecorator<int>();
    private IsDirtyDecorator<string> MyString = new IsDirtyDecorator<string>();

    public MyClass()
    {
        MyInt.Value = 123;
        MyString.Value = "Hello";
        Console.WriteLine(MyInt.Value);
        Console.WriteLine(MyInt.IsDirty);
        Console.WriteLine(MyString.Value);
        Console.WriteLine(MyString.IsDirty);
    }
}
于 2011-02-15T21:39:38.443 に答える
2

シンプルにすることも複雑にすることもできます。それはあなたが投資したい仕事の量に依存します。アスペクト指向プログラミングを使用して、IL ウィーバーを介してPostSharpなどの IL コードにアスペクトを追加できます。または、プロパティの状態を処理する単純なクラスを作成できます。非常に単純であるため、前者のアプローチは、この方法で処理するプロパティが非常に多い場合にのみ有効です。

using System;

class Dirty<T>
{
    T _Value;
    bool _IsDirty;

    public T Value
    {
        get { return _Value; }
        set
        {
            _IsDirty = true;
            _Value = value;
        }
    }

    public bool IsDirty
    {
        get { return _IsDirty; }
    }

    public Dirty(T initValue)
    {
        _Value = initValue;
    }
}

class Program
{
    static Dirty<int> _Integer;
    static int Integer
    {
        get { return _Integer.Value; }
        set { _Integer.Value = value;  }
    }

    static void Main(string[] args)
    {
        _Integer = new Dirty<int>(10);
        Console.WriteLine("Dirty: {0}, value: {1}", _Integer.IsDirty, Integer);
        Integer = 15;
        Console.WriteLine("Dirty: {0}, value: {1}", _Integer.IsDirty, Integer);
    }
}

別の可能性は、実行時に生成されるプロキシ クラスを使用することです。これにより、アスペクトが追加されます。.NET 4 では、この側面を既に処理するクラスがあります。プロパティが変更されたときにイベントを介して通知するExpandObjectと呼ばれます。良い点は、ExpandoObject を使用すると、実行時に任意の量のプロパティを定義でき、プロパティのすべての変更について通知を受け取ることができることです。この型を使用すると、WPF でのデータバインディングが非常に簡単になります。

dynamic _DynInteger = new ExpandoObject();

_DynInteger.Integer = 10;
((INotifyPropertyChanged)_DynInteger).PropertyChanged += (o, e) =>
{
    Console.WriteLine("Property {0} changed", e.PropertyName);
};

Console.WriteLine("value: {0}", _DynInteger.Integer );
_DynInteger.Integer = 20;
 Console.WriteLine("value: {0}", _DynInteger.Integer);

さようなら、アロイス・クラウス

于 2011-02-15T22:11:07.973 に答える
2

Simon Hughes の回答に追加します。私は同じことを提案しますが、デコレータ クラスがグローバル IsDirty フラグを自動的に更新できるようにする方法を追加します。昔ながらの方法で行う方が複雑ではないことに気付くかもしれませんが、公開するプロパティの数と、同じ機能を必要とするクラスの数によって異なります。

public class IsDirtyDecorator<T>
{
    private T _myValue;
    private Action<bool> _changedAction;

    public IsDirtyDecorator<T>(Action<bool> changedAction = null)
    {
        _changedAction = changedAction;
    }

    public bool IsDirty { get; private set; }

    public T Value
    {
        get { return _myValue; }
        set
        {
            _myValue = value;
            IsDirty = true;
            if(_changedAction != null)
                _changedAction(IsDirty);
        }
    }
}

これで、別のクラスの他の IsDirty プロパティをデコレータ クラスに自動的に更新させることができます。

class MyObject
{
    private IsDirtyDecorator<int> _myInt = new IsDirtyDecorator<int>(onValueChanged);
    private IsDirtyDecorator<int> _myOtherInt = new IsDirtyDecorator<int>(onValueChanged);

    public bool IsDirty { get; private set; }

    public int MyInt
    {
        get { return _myInt.Value; }
        set { _myInt.Value = value; }
    }

    public int MyOtherInt
    {
        get { return _myOtherInt.Value; }
        set { _myOtherInt.Value = value; }
    }

    private void onValueChanged(bool dirty)
    {
        IsDirty = true;
    }

}
于 2011-02-15T22:35:05.873 に答える
1

そのような一般的な操作を行うカスタムProperty<T>クラスを作成しました。まだ完全には使用していませんが、このシナリオでは使用できます。

コードはここにあります: http://pastebin.com/RWTWNNCU

次のように使用できます。

readonly Property<int> _myInt = new Property<int>();
public int MyInt
{
    get { return _myInt.GetValue(); }
    set { _myInt.SetValue( value, SetterCallbackOption.OnNewValue, SetDirty ); }
}

private void SetDirty( int oldValue, int newValue )
{
    IsDirty = true;
}

Property クラスは、パラメーターのおかげで新しい値が渡されたときに、渡されたデリゲートの呼び出しのみを処理しSetterCallbackOptionます。これはデフォルトであるため、削除できます。

アップデート:

intデリゲートが一致しないため、複数のタイプ( 以外)をサポートする必要がある場合、これは明らかに機能しません。もちろん、ニーズに合わせてコードをいつでも調整できます。

于 2011-02-15T21:50:19.907 に答える