2011-04-06 90 views
4

我有一個(現有的)類型類項:類型化<> /無類型設計

Items<T> 
    T Value { get; } 

T可以是雙,字符串或者int。

然後,我有一個類,必須持有幾個項目的實例。在這個類的單個實例中,T總是相同的。既然這樣,實際包含的類型是由屬性確定,並且該容器不鍵入:

Data 
    DataType { get; set; } 
    Items<double> 
     double Value; 
    Items<string> 
     // ... and so on. Nasty stuff. 

在理想情況下,當然,這將是

Data<T> 
    Items<T> 
     T value 

數據實例是從頭在代碼創建,並且可以從數據庫加載。所以當然,我們將來會有一個工廠,但Create方法的返回類型是什麼?

更糟糕的是,我需要這樣的:

DataCollection 
    // HERE'S THE PAIN: What's the type here? 
    List of Data<> instances with differing types 

foreach (? data in someDataCollection) 
    if (thetypeof data is double) 
     doSomething(); 
    else 
     doSomethingElse(); 

現在,我可以解決這個問題,但我看不到解決這個乾淨的方法。

我的第一個問題是DataCollection的聲明。列表的類型是什麼?名單<對象>,所以它可以容納數據<雙>和數據<字符串>?

+1

請出示實際的代碼,而不是僞代碼。 – 2011-04-06 16:49:48

回答

5

實際上有一個乾淨的方法來解決這個問題;您可以使用帶有數據類型和值的鍵的字典,類型爲泛型Func <>。然後,將該類型傳遞給create方法,然後該方法根據類型查找Func <>以在Dictionary中使用,並調用Func <>來創建或處理對象。

由於我是從僞代碼工作,基本上它看起來像下面的東西;你可以玩它並修改它以滿足你的需求,但這是基本的想法。

首先,爲所有數據對象創建一個父類;注意,這個類有一個查找字典功能,各類調用,並請注意,這是抽象的:

public abstract class Data 
{ 

    // A Lookup dictionary for processing methods 
    // Note this the functions just return something of type object; specialize as needed 
    private static readonly IDictionary<Type, Func<object, Data>> _processFunctions = new Dictionary 
     <Type, Func<object, Data>>() 
     { 
      {typeof(int), d => { return doSomethingForInt((Data<int>) d); }}, 
      {typeof(string), d => { return doSomethingForString((Data<string>) d); }}, 
      {typeof(double), d => { return doSomethingForDouble((Data<double>) d); }}, 

     }; 

    // A field indicating the subtype; this will be used for lo 
    private readonly Type TypeOfThis; 

    protected Data(Type genericType) 
    { 
     TypeOfThis = genericType; 
    } 

    public Data Process() 
    { 
     return _processFunctions[this.TypeOfThis](this); 
    } 

} 

現在子類數據與泛型類型可實例:

class Data<T> : Data 
{ 

    // Set the type on the parent class 
    public Data() : base(typeof(T)) 
    { 
    } 

    // You can convert this to a collection, etc. as needed 
    public T Items { get; set; } 

    public static Data<T> CreateData<T>() 
    { 
     return new Data<T>(); 
    } 
} 

你然後可以使用父類型創建一個DataCollection類。請注意ProcessData()方法;它現在所做的就是循環遍歷元素並在每個元素上調用Process():

class DataCollection 
{ 
    public IList<Data> List = new List<Data>(); 

    public void ProcessData() 
    { 
     foreach (var d in List) 
     { 
      d.Process(); 
     } 
    } 

} 

...而且你們都已經設置!現在你可以用不同類型的數據調用您的數據收集:

DataCollection dc = new DataCollection(); 

dc.List.Add(new Data<int>()); 
dc.List.Add(new Data<string>()); 
dc.List.Add(new Data<double>()); 


dc.ProcessData(); 
+0

不錯,但我還是一個級別:DataCollection是什麼樣的? – Stu 2011-04-06 17:19:02

+0

更具體地說,我需要一個包含「Data 」和「Data 」的集合。也就是說,集合**沒有T **。 – Stu 2011-04-06 17:24:32

+0

如果我做了'Data fooData = Data.CreateData ()'後面跟着'Data.Process(fooData);' – 2011-04-06 17:48:45

1

我認爲每一個你需要做的時間,如果條件運行時的數據類型,這意味着有一些錯誤的數據結構。但是每次遇到這樣的情況,我都很難解決這個問題。

我想在這裏做的是將你的原始類型轉換爲某種具有轉換方法的適配器(甚至可能是隱式的),並讓它們都實現一個通用接口,比如說​​。然後,您可以分別在IntWrapperDoubleWrapper等中定義doSomething行爲。那麼你的DataCollection應該是List<IDoSomething>類型,並且循環可以從接口調用data.DoSomething()方法。

有隱式轉換,您可以使用集合像data.Add(3)自然的方式 - 你仍然可以添加項目,而不包裹privitives

+0

'data.add(3)'不起作用。你會得到'Argument'1'的編譯錯誤:不能從'int'轉換爲'IDoSomething''你仍然需要'data.Add(IntWrapper(3))' – 2011-04-06 18:16:26

相關問題