2012-10-13 83 views
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值)),則構造類型值的三個不同的變量(A,B,C)以這樣的方式,當我打電話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; 
    } 
} 

解決方案: 一個簡單的反射和無收集的解決方案是使用回答另一個問題(Emulating delegates with free generic type parameters in C#Emulating delegates with free generic type parameters in C#)發現。解決方案是Delegates to generic operations where the generic type is unknown. How to create something like that?

+1

你能改說這個問題嗎?我沒有得到你想要做的。 – GregRos

+0

改寫了這個問題。 –

回答

0

問題證明是可以解決的。 Mike-z爲我提供了一個幾乎正確的解決方案,用於解決通用方法問題(Emulating delegates with free generic type parameters in C#),我將其修改爲一個完整的解決方案:(Emulating delegates with free generic type parameters in C#)。

這個問題的解決方案也變得簡單了。接口可以包含泛型方法,我們可以使用接口值變量來存儲指向泛型方法的鏈接,而無需指定具體的類型參數。以下代碼利用Store<T>類不加修改,並使用ISetter接口和ASetter/BSetter/CSetter「閉包」來保存對不同通用成員的引用。 Value類將參考存儲在ISetter-type變量中,並使用_setter鏈接到的通用成員,一旦類型參數T變爲可用。

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); 
    } 
} 
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>任何參考。


UPDATE

意識到這一點的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在同一時間!因爲這四個不同的A's存在四個不同的Store<T>

+0

也許我沒有正確地理解這個問題,但這是來自於一個問題:'我想探索一個不涉及字典或類似的解決方案' –

+0

是的,你可以使用switch語句而不是數組;然而,就我所知,如果switch語句有足夠的情況,C#編譯器可以決定使用散列表來實現switch-statement。所以一本字典會在引擎蓋下被使用。你必須用不使用泛型類型參數的東西來初始化'Value'對象,因爲這樣的參數是在方法級別定義的,並且構造函數不知道。我所看到的唯一的另一種可能性是使用if-else-if-chain,但如果存儲多個值,這不是很優雅。 –

+0

不幸的是,這個解決方案就是我所說的「涉及字典或類似的東西的解決方案」。 –