私は、プログラマー アプリケーションの根底にあり、特定のデータへのアクセスを検出する必要があるシステムを作成しています。私はほとんどの場合、次のようにプロパティを使用してこれを行うことができます。
public class NiceClass {
public int x { get; set; }
}
次に、アクセスを適切に処理できるようにアクセサーget
とアクセサーを微調整します。set
ただし、これには、ユーザー (アプリケーション プログラマー) がすべてのデータをプロパティとして定義する必要があります。
ユーザーが (プロパティではなく) 「通常の」フィールドを持つ既存のクラスを使用したい場合、それらのアクセスを検出できません。例:
public class NotSoNiceClass {
public int y;
}
へのアクセスを検出できませんy
。ただし、既存のクラスの使用を許可したいと考えています。妥協点として、そのようなデータへのアクセスが発生するたびに、ユーザーは私に通知する責任があります。例えば:
NotSoNiceClass notSoNice;
...
Write(notSoNice.y, 0); // (as opposed to notSoNice.y = 0;)
そんな感じ。信じてください、私はこれを非常に徹底的に調査しましたが、アクセスを検出するためにバイトコードを直接分析することでさえ、間接的な可能性などのために信頼できません.私は本当にユーザーに私に通知してもらう必要があります.
そして今、私の質問: これらの通知を実行するための「エレガントな」方法をお勧めできますか? (はい、私はこの状況全体がそもそも「エレガント」ではないことを知っています;私はそれを悪化させないようにしています;))。どのようにしますか?
実際の状況は次のようなものであるため、これは私にとって問題です:私は次のクラスを持っています:
public class SemiNiceClass {
public NotSoNiceClass notSoNice { get; set; }
public int z { get; set; }
}
ユーザーがこれを行いたい場合:
SemiNiceClass semiNice;
...
semiNice.notSoNice.y = 0;
代わりに、次のようにする必要があります。
semiNice.Write("notSoNice").y = 0;
WhereWrite
は のクローンを返します。これは、とにかくアクセサに実行してnotSoNice
ほしかったことです。set
ただし、文字列を使用するのはかなり醜いです。後でフィールドをリファクタリングする場合、Write("notSoNice")
アクセスを調べて文字列を変更する必要があります。
どのようにフィールドを識別できますか? 文字列、整数、列挙型 (つまり、整数) しか考えられません。しかし:
- 文字列の問題についてはすでに説明しました。
- イントは苦痛です。ユーザーはどの int がどのフィールドに対応するかを覚えておく必要があるため、さらに悪いことになります。リファクタリングも同様に困難です。
- 列挙型 ( や など
NOT_SO_NICE
、Z
つまり のフィールドSemiNiceClass
) はリファクタリングを容易にしますが、ユーザーはクラスごとに列挙型 (SemiNiceClass
など) を、クラスのフィールドごとに値を記述する必要があります。気に障る。彼らに嫌われたくないです;)
では、なぜ私たちはこれを行うことができないのでしょうか?
semiNice.Write(semiNice.notSoNice).y = 0;
どのフィールドがアクセスされているかを知る必要がありsemiNice.notSoNice
、フィールドを識別しないためです。フィールド自体ではなく、フィールドの値です。
はぁ。私はこれが醜いことを知っています。私を信じてください ;)
提案をいただければ幸いです。
前もって感謝します!
(また、この質問に対する適切なタグが思いつきませんでした。より良いアイデアがあればお知らせください。編集します)
編集 #1: Hightechrider の提案: 式。
Write(x =>semiNice.y, 0)
質問のために書いたクラス ( など) に基づいているSemiNiceClass
のか、それとも単なる例なのかはわかりませんが、前者の場合は構造と一致しません: にy
フィールドがありませんSemiNiceClass
。ということWrite(x =>semiNice.notSoNice.y, 0)
ですか?
これをどのように使用するつもりなのかわかりません...私が書いたコードを投稿します:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Test.MagicStrings {
public class MagicStringsTest {
public static void Main(string[] args) {
SemiNiceClass semiNice = new SemiNiceClass();
// The user wants to do: semiNice.notSoNice.y = 50;
semiNice.Write(x => semiNice.notSoNice.y, 50);
}
}
public class SemiNiceClass {
public NotSoNiceClass notSoNice { get; set; }
public int z { get; set; }
public SemiNiceClass() {
notSoNice = new NotSoNiceClass();
}
public void Write(Func<object, object> accessor, object value) {
// Here I'd like to know what field (y, in our example) the user wants to
// write to.
}
}
public class NotSoNiceClass {
public int y;
}
}
でその情報を取得するにはどうすればよいWrite
ですか? からその情報を抽出する方法が見つかりませんFunc<,>
。また、何にも使用していないのに、なぜsemiNice.Write(x => semiNice.notSoNice.y, 50);
の代わりに書くのですか?semiNice.Write(() => semiNice.notSoNice.y, 50);
x
ありがとう。
編集 #2: Hans Passant の提案: フィールドをプロパティに置き換えます。
これは私が最初に意図したことですが、再コンパイルはオプションではありません。
編集 #3 : Ben Hoffstein の提案: 動的プロキシ。リンフー。
私はすでにこれを長く懸命に調べてきましたが、比較的複雑な理由で使用できません。説明するには長くなりすぎますが、安心してください。それは私の現在のソリューションよりもはるかにきれいです。