0

次のコードがあるとします。

static class Store<T> {
    public static T A;
    public static T B;
    public static T C;
}

public static class Store {
    public static Value A = new Value(<T>(v) => Store<T>.A = v); //just an example of what I want
    public static Value B = new Value(<T>(v) => Store<T>.B = v); //just an example of what I want
    public static Value C = new Value(SetC<T>);  //just an example of what I want

    public static void SetA<T>(T value) { Store<T>.A = value; }
    public static void SetB<T>(T value) { Store<T>.B = value; }
    public static void SetC<T>(T value) { Store<T>.C = value; }
}

public class Value {
    Action<T><T> _valueChanger; //just an example of what I want
    public Value(Action<T><T> valueChanger) { //just an example of what I want
        _valueChanger = valueChanger;
    }

    public void SetValue<T> (T value) {
        _valueChanger<T>(value); //just an example of what I want
    }
}

Store.A.SetValue(42)に値が保存されるように書きたいStore<int>.A。それを実現するには、「私が望むものの単なる例」でマークされた行の代わりに何を書くことができますか? (辞書などを使用しないソリューションを検討したい)

質問 を言い換えると、クラスを変更しValue(いくつかのフィールドを定義し、コンストラクターを記述し、メソッド Value.SetValue(T value) を記述します)、次のような方法で Value (A、B、C) 型の 3 つの異なる変数を構築します。呼び出すとStore.A.SetValue(42)、値Store<int>.Aが 42 に変更されます。

クラスの別のバリエーション:

static class Holder<T> {
    T Value { get; set; }
}

static class Store2<T> {
    public static Holder<T> A = new Holder<T>();
    public static Holder<T> B = new Holder<T>();
    public static Holder<T> C = new Holder<T>();
}

public static class Store2 {
    public static Value A = new Value2(Store2<>.A); //just an example of what I want
    public static Value B = new Value2(Store2<>.B); //passing non-specific generic expression
    public static Value C = new Value3({TFree}() => Store2<TFree>.C); //just an example of what I want
}

public class Value2 { //Non-generic class!
    Holder{TFree}<TFree> _holder; //just an example of what I want
    public Value(Holder{TFree}<TFree> holder) { //just an example of what I want
        _holder = holder;
    }

    public void SetValue<T> (T value) {
        _holder{T}.Value = value; //just an example of what I want
    }
}

public class Value3 { //Non-generic class! (Another variation)
    Func{TFree}<Holder<TFree>> _holderFactory; //just an example of what I want

    public Value(Func{TFree}<Holder<TFree>> holderFactory) { //just an example of what I want
        _holderFactory = holderFactory;
    }

    public void SetValue<T> (T value) {
        Holder<T> holder = _holderFactory{T}(); //just an example of what I want
        holder.Value = value; 
    }
}

解決策: 別の質問 ( C#で無料のジェネリック型パラメーターを使用してデリゲートをエミュレートするおよびC# で無料のジェネリック型パラメーターを使用してデリゲートをエミュレートする ) への回答を使用して、リフレクションとコレクションを使用しない簡単な解決策が見つかりました。解決策は、ジェネリック型が不明なジェネリック操作へのデリゲートです。そのようなものを作成する方法は?.

4

2 に答える 2

0

配列を使用して値を格納し、インデックスを使用してプロパティを介して値にアクセスします

public static class Store<T>
{
    public static readonly T[] Values = new T[3];
    public static T A { get { return Values[0]; } set { Values[0] = value; } }
    public static T B { get { return Values[1]; } set { Values[1] = value; } }
    public static T C { get { return Values[2]; } set { Values[2] = value; } }
}

public static class Store
{
    public static readonly Value A = new Value(0);
    public static readonly Value B = new Value(1);
    public static readonly Value C = new Value(2);
}

public class Value
{
    private int _index;

    public Value(int index)
    {
        _index = index;
    }

    public void SetValue<T>(T value)
    {
        Store<T>.Values[_index] = value;
    }

    public T GetValue<T>()
    {
        return Store<T>.Values[_index];
    }
}

のコンストラクターはValueジェネリック型パラメーターを認識しないため、特定のを参照することはできませんStore<T>


アップデート

Store<T>に指定した個別の型引数ごとにのコピーが作成されることに注意してくださいT。この例を参照してください

Store.A.SetValue(42);
Store.A.SetValue("Douglas Adams");
Store.A.SetValue(new DirectoryInfo(@"C:\"));
Store.A.SetValue(new List<int>());

var x1 = Store.A.GetValue<int>();           // --> 42
var x2 = Store.A.GetValue<string>();        // --> "Douglas Adams"
var x3 = Store.A.GetValue<DirectoryInfo>(); // --> DirectoryInfo{ C:\ }
var x4 = Store.A.GetValue<List<int>>();     // --> List<int>{ Count = 0 }

Aデバッガーを使用すると、4つの異なる値が同時に格納されていることがわかります。原因として、これらは4つの異なるA'sものに存在する4つの異なるものStore<T>です。

于 2012-10-13T23:08:11.270 に答える
0

問題は解決可能であることが判明しました。Mike-z は、デリゲートからジェネリック メソッドへの問題 ( C# で無料のジェネリック型パラメーターを使用してデリゲートをエミュレートする)のほぼ正しい解決策を提供してくれました。.

この質問の解決策も簡単になります。インターフェイスにはジェネリック メソッドを含めることができ、インターフェイス値の変数を使用して、具体的な型引数を指定せずにジェネリック メソッドへのリンクを格納できます。次のコードは、Store<T>クラスを変更せずに利用し、ISetterインターフェイスと「クロージャー」を使用して // さまざまなジェネリック メンバーへの参照を保持しますASetter。クラスは型付き変数に参照を格納し、型引数が使用可能になるとリンクする汎用メンバーを使用します。BSetterCSetterValueISetter_setterT

public interface ISetter {
    void SetValue<T>(T value);
}

public static class Store {
    public static Value A = new Value(new ASetter());
    public static Value B = new Value(new BSetter());
    public static Value C = new Value(new CSetter());

    class ASetter : ISetter {
        public void SetValue<T>(T value) { Store<T>.A = value; }
    }
    class BSetter : ISetter {
        public void SetValue<T>(T value) { Store<T>.B = value; }
    }
    class CSetter : ISetter {
        public void SetValue<T>(T value) { Store<T>.C = value; }
    }
}

public class Value {
    ISetter _setter;

    public Value(ISetter setter) {
        _setter = setter;
    }

    public void SetValue<T> (T value) {
        _setter.SetValue<T>(value);
    }
}
于 2012-10-19T03:43:20.783 に答える