3

外部プログラムがクラス内の変数を取得/設定するための簡単な方法を作成しようとしています。私が持っているのは、次のようないくつかの変数を持つクラスです。

class myClass
{
    public int one
    {
        get{ /* get code here */ }
        set{ /* set code here */ }
    }
}

単なる変数「1つ」ではなく、100近くの変数があります。getおよびsetコードを使用して、すべて同じ方法で設定されます。私が欲しいのは、変数を取得して設定する簡単な方法です。例:これを行う代わりに:

myClass c = new myClass();
c.one = 5;

私はこれに似た何かをする方法を見つけたいと思います:

myClass c = new myClass();
c.setVariable("variableName", value);

「variableName」テキストを列挙型リストから取得して、次のように参照できるようにすることが理想的です。

c.setVariable(enumName.varName, value);

どうすればいいのか、それが可能かどうかもわかりません。私が言ったように、私は独自のget / setコードを必要とする100近くの変数を持っていますが、さまざまな理由から、1つのpublicget関数と1つのpublicset関数だけを使用したいと思います。

リフレクションはあまり効率的ではないと思いますので、なるべく避けたいと思います。

このようなものが使用されているC#の他のコードを見たことがあります:

this["variableName"] = value;

しかし、私もこれを機能させる方法を見つけることができないようです...

4

3 に答える 3

7
this["variableName"] = value;

説明する構文は、辞書に対してのみ有効です。また、リフレクションを使用せず、単一のゲッターとセッターのみが必要な場合は、辞書を使用する必要があります。編集:ラムダ式について知っていますか?それらはインラインの匿名メソッドであり、それらを別の辞書に入れることで検証を行うことができます!このようなもの:

public class MyClass
{
    private readonly Dictionary<String, Object> dictionary;
    private readonly Dictionary<String, Func<Object, bool>> validators;

    public MyClass()
    {
        this.dictionary = new Dictionary<String, Object>();
        this.validators = new Dictionary<String, Func<Object, bool>>();

        // Put the default values in the dictionary.
        this.dictionary["One"] = 10;
        this.dictionary["Another"] = "ABC";

        // The validation functions:
        this.validators["One"] = obj => ((int)obj) >= 0;
        this.validators["Another"] = obj => obj != null;
    }

    public Object this[string name]
    {
        get { return this.dictionary[name]; }
        set
        {
            // This assumes the dictionary contains a default for _all_ names.
            if (!this.dictionary.Contains(name))
                throw new ArgumentException("Name is invalid.");

            // Get a validator function. If there is one, it must return true.
            Func<Object, bool> validator;
            if (validators.TryGetValue(name, out validator) &&
                !validator(value))
                throw new ArgumentException("Value is invalid.");

            // Now set the value.
            this.dictionary[name] = value;
        }
    }
}

このコードについて注意すべき点がいくつかあります。

  • ディクショナリはジェネリックオブジェクトです:Dictionary Of String and Object、ここStringで、はキーObjectのタイプであり、は値のタイプです。値の種類が1つしかない場合(たとえば整数)、Objectどこでもたとえばに変更する必要がありますint
  • インスタンスが与えられると、の値を設定するためにMyClass myClass行うことができます。myClass["One"] = 20One
  • (うっかりして)存在しない名前の値を取得しようとすると(var value = myClass["DoesNotExist"])、例外が発生します。これを変更してデフォルト値を返すか、まったく別のことを行うことができます。
  • を使用するenumには、コードではなく列挙型を作成してそのタイプを指定しStringます。
于 2013-02-22T01:24:33.040 に答える
1

別の解決策は、次のようにリフレクションを使用することです。

public object this[string name] {
    get { return this.GetType().GetProperty(name).GetValue(this, null); }
    set { this.GetType().GetProperty(name).SetValue(this, value, null); }
}

また:

public void SetVariable(string name, object value){
    this.GetType().GetProperty(name).SetValue(this, value, null); 
}
于 2013-02-22T01:41:17.577 に答える
0

デザインについてはコメントしませんが、実装はかなり簡単です。リフレクションはまったく必要ありません。たくさんのタイピングが必要です。一般的に、あなたが望むのは基本的にこれです:

public class MyClass
{
    public enum Variables {
        one,
        two
    }

    private int one {
        get { /* get; */ }
        set { /* set; */ }
    }

    private int two {
        get { /* get; */ }
        set { /* set; */ }
    }

    public object getVariable(Variables v) {
        switch(v) {
            case Variables.one: return one;
            case Variables.two: return two;

            default: throw new InvalidArgumentException("v");
        }
    }

    public void setVariable(Variables v, object value) {
        switch(v) {
            case Variables.one: one = (int)value; return;
            case Variables.two: two = (int)value; return;

            default: throw new InvalidArgumentException("v");
        }
    }
}

なぜなら、あなたはタイプチェックを受けていないので、多くのことがあなたの顔に吹き飛ばされる可能性があります。パフォーマンスに過度の負担をかけずにリフレクションを使用してこれを行う別の方法は、enum->getterおよびenum->setterメソッド(MethodInfoだけでなくデリゲート)のディクショナリを静的にコンパイルすることです。これにより、起動時のパフォーマンスが低下します。ただし、値を取得および設定するときに、パフォーマンスを(特に)損なうことはありません。

[編集]
上記は次のように実装することもできます。

public object this[Variables v]
{
    get { return getVariable(v); /* or move implementation here */ }
    set { serVariable(v, value); /* or move implementation here */ }
}

これにより、(たとえば)を書くことができますmyObject[MyClass.Variables.one] = 5

[編集2]
以下動作テスト済みです。通常の反射(またはそのことについては巨大なスイッチ)に対抗したときのパフォーマンスについてはわかりません。

于 2013-02-22T01:37:50.587 に答える