自動プロパティのバッキングフィールドへのアクセス
-
19-08-2019 - |
質問
検証、変更追跡などを行うために、プロパティのバッキングフィールドにアクセスする方法はありますか?
次のようなことは可能ですか?そうでない場合は、.NET 4 / C#4で使用する予定はありますか?
public string Name
{
get;
set
{
if (value != <Keyword>)
{
RaiseEvent();
}
<Keyword> = value;
}
}
主な問題は、自動プロパティを使用しても、明示的なバッキングフィールドを持つプロパティとは異なり、検証などの柔軟性が得られないことです。ただし、明示的なバッキングフィールドには、アクセスする必要があるときに含まれているクラスがバッキングフィールドにアクセスすることを許可するいくつかの状況で不利な点があります。プロパティを外部的に。
上記の例では、バッキングフィールドへのアクセスがプロパティにスコープされるため、プロパティの検証、変更追跡などの回避が防止されます。
編集: <!> lt;を変更しました。バッキングフィールド<!> gt; <!> lt;キーワード<!> gt;。値に似た新しいキーワードを提案します。 field は、既存の多くのコードで使用されていると確信していますが、うまくいきます。
解決
Mehrdadの回答にあるコメントを読んで、あなたの問題をもう少しよく理解できたと思います。
開発者が作成中のクラスのプライベート状態にアクセスしたり、検証ロジックをバイパスしたりすることを懸念しているようです。これは、状態がクラスにまったく含まれないことを示唆しています。
次の戦略を提案します。 ValidatedValueを表すジェネリッククラスを記述します。このクラスはバッキング値のみを保持し、getおよびsetメソッドを介したアクセス/変更のみを許可します。検証ロジックを表すために、ValidatedValueにデリゲートが渡されます。
public class ValidatedValue< T >
{
private T m_val;
public ValidationFn m_validationFn;
public delegate bool ValidationFn( T fn );
public ValidatedValue( ValidationFn validationFn )
{
m_validationFn = validationFn;
}
public T get()
{
return m_val;
}
public void set(T v)
{
if (m_validationFn(v))
{
m_val = v;
}
}
}
もちろん、必要に応じて(たとえば、変更前後の通知をサポートするために)デリゲートを追加できます。
クラスは、プロパティのバッキングストアの代わりにValidatedValueを使用します。
以下の例は、100未満であると検証された整数を持つMyClassクラスを示しています。例外をスローするロジックは、ValidatedValueではなくMyClassにあることに注意してください。これにより、MyClassに含まれる他の状態に依存する複雑な検証ルールを実行できます。検証デリゲートの構築にはラムダ表記が使用されました-代わりにメンバー関数にバインドすることもできます。
public partial class MyClass
{
private ValidatedValue<int> m_foo;
public MyClass()
{
m_foo = new ValidatedValue<int>(
v =>
{
if (v >= 100) RaiseError();
return true;
}
);
}
private void RaiseError()
{
// Put your logic here....
throw new NotImplementedException();
}
public int Foo
{
get { return m_foo.get(); }
set { m_foo.set(value); }
}
}
それが役立つことを願っています-元のトピックから多少外れていますが、実際の懸念とはより一致していると思います。行ったのは、検証ロジックをプロパティから取り去り、それをデータに配置することです。これはまさにあなたが望んだ場所です。
他のヒント
いいえ、ありません。バッキングフィールドにアクセスする場合は、自動プロパティを使用せず、独自のプロパティをロールバックします。
クラスの残りの部分ではなく、プロパティのみがアクセスできるフィールドを持つことは素晴らしいことであることに同意します。私はいつもそれを使います。
MSDN の状態:
<!> quot; C#3.0以降では、自動実装 プロパティはプロパティ宣言を行います 追加のロジックがない場合、より簡潔に プロパティアクセサには必須です。 また、クライアントコードを作成できるようにします オブジェクトとしてプロパティを宣言するとき 次の例に示すように、 コンパイラはプライベートな匿名を作成します バッキングフィールドにのみアクセスできます プロパティの取得および設定を通じて アクセサ。<!> quot;
アクセサーに追加のロジックがあるため、自動実装プロパティの使用はシナリオに適していません。
バッキングフィールドは存在しますが、簡単に参照するのをやめるために、マングルされた名前が付けられています-そのアイデアは、フィールドを直接参照しないことです 。興味のために、Reflectorを使用してコードを逆アセンブルし、フィールド名を検出できますが、この名前は実際には揮発性である可能性があるため、フィールドを直接使用しないことをお勧めします。コードはいつでも壊れる可能性があります。
いいえ、ただしサブクラスに含めることができます:
public class Base
{
public string Name
{
get;
virtual set;
}
}
public class Subclass : Base
{
// FIXME Unsure as to the exact syntax.
public string Name
{
override set
{
if (value != base.Name)
{
RaiseEvent();
}
base.Name = value;
}
}
}
そうするつもりなら、なぜ自動プロパティを使用しているのですか?
単純なプロパティにより、1.0に戻りました。特殊なケースごとに言語を複雑にすることは理にかなっていないと思います。単純なストア/取得モデルを実行するためにプロパティが必要か、それ以上が必要です。後者の場合、通常のプロパティで十分です。
これを行うことはできません。それが、 MoXAML Power Toys の作成を開始した理由の1つです。自動プロパティをNotifyプロパティに変換します。