2010-08-19 35 views
2

我有一組實現接口(IMyClass)的類(MyClass1, MyClass2, MyClass3)。使用通用類型或接口的C#集合

我感興趣的創建方法來填充,並返回有共同的接口MyClassXList<IMyClass>)對象的列表(Collection.Generics.Lists<>)。但是如何?

每個班級都有一個構造函數MyClassX它做了一些不同的事情。所以我不能創建一個BaseClass併爲所有人使用通用構造函數。

通過界面我不能這樣做:

public List<IMyClass> Fill(string[] ItemsPassedByParam, IMyClass InstanceOfMyClassX) 
    List MyList = new List<IMyClass>(); 
    foreach (item in ItemsPassedByParam) 
    { 
     MyList.Add (new IMyClass (item)); //can't do new from an Interface!! 
    } 
} 

我也嘗試過使用泛型類型,TMyClass在下面的例子,但也很適合我(雖然我不是泛型類型非常深刻的概念):

public List<TMyClass> Fill(string[] ItemsPassedByParam, Type TypeOfMyClassX) 
    List MyList = new List <TMyClass>(); 
    foreach (item in ItemsPassedByParam) 
    { 
     MyList.Add (new TMyClass (item)); //can't do new from a Generic Type!! 
    } 
} 

我試圖也來外部的MyClassX在方法的構造內的代碼,但我不能調用該方法因爲去對象未初始化(沒有new())。

在這些情況下是哪種解決方案?

提前致謝!

+0

什麼是'item'?它是否確定類型? – cjk 2010-08-19 15:26:42

+0

此外,什麼是 「新目錄();」應該是?沒有什麼可以想象的編譯。 – 2010-08-19 15:28:25

回答

7

這聽起來像你想的填充方法來創建從字符串值傳遞的一個List<T>,其中T是推導IMyClass

您需要做的是將工廠函數傳遞給Fill方法,該方法允許創建IMyClass派生實例。

public List<IMyClass> Fill(
    string[] ItemsPassedByParam, 
    Func<string,IMyClass> createFunc) 

    List MyList = new List<IMyClass>(); 
    foreach (item in ItemsPassedByParam) { 
    MyList.Add(createFunc(item));   
    } 
} 

然後,在你打電話填補你可以選擇使用

string[] items = ...; 
List<IMyClass> list1 = Fill(items, item => new MyClass1(item)); 
List<IMyClass> list2 = Fill(items, item => new MyClass2(item)); 
+0

謝謝Jared! 我做了你和賈斯汀Niessner的解決方案之間的混合。因爲關於女巫的開發時間提醒是使用構造函數對我來說不是很實用。所以我做了一個'MyClassFactory.CreateInstance()'也是一個'MyClassFactory.GetConstrucor(類型)'來獲得撥款的構造。 – Alex 2010-08-20 11:37:08

2

這裏最好的選擇是創建一個處理取參數IMyClassFactory,搞清楚構建哪個具體類型,調用構造函數,並返回它:

public class IMyClassFactory 
{ 
    public static IMyClass CreateInstance(string item) 
    { 
     switch(item) 
     { 
      case "SomeValue": 
      case "SomeValue2": 
       return new MyClass1(item); 
      case "SomeOtherValue": 
       return new MyClass2(item); 
     } 
    } 
} 

那家工廠顯然假定您可以推斷鍵入從傳入工廠的字符串。很有可能情況並非如此,在這種情況下,您需要添加另一個參數,以便您推斷要實例化的具體類型。

一旦你的工廠,那麼你可以讓你的原來的方法使用該工廠:

public List<IMyClass> Fill(string[] ItemsPassedByParam) 
{ 
    List MyList = new List<IMyClass>(); 

    foreach (item in ItemsPassedByParam) 
    { 
     MyList.Add(IMyClassFactory.CreateInstance(item)); 
    } 
} 
+1

IMyClassFactory?用「我」?該命名約定會導致混淆... – 2010-08-19 15:31:01

+0

謝謝賈斯汀! 按照你的方法我建你'MyClassFactory.CreateInstance()',也做了'MyClassFactory.GetConstrucor(T型)'用賈裏德 解決方案。 – Alex 2010-08-20 11:40:03

1

也許你可以只使用工廠模式在這裏,這取決於你如何判斷需要哪種類型的其中IMyClass推導的地方。

也許您需要使用反射並調用ConstructorInfo(將參數傳遞給構造函數,返回一個對象,適合在模板方法中構建,但也適用於在運行時炸燬在編譯時會被捕獲的東西)。

後者似乎離你最近一直在嘗試什麼,但如果你可以從一個更類型安全的工廠做的事情,然後這可能是要走的路。

public static T BuildOne(SomeParamType myParam) 
{ 
    ConstructorInfo constrInfo = typeof(T).GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, new Type[]{typeof(SomeParamType)}, null); 
    return (T)constrInfo.Invoke(new object[]{myParam}); 
} 
2

不能創建一個接口的實例,但你可以創建一個通用型的實例 - 只要它有一個默認的構造函數。您可以將該項目傳遞給實例,而不是使用構造函數注入。

public List<TMyClass> Fill(string[] ItemsPassedByParam) 
    where TMyClass : IMyClass, new() { 
    ... 
     IMyClass inst = new TMyClass(); 
     inst.SetItem(item); 
     myList.Add(inst); 
    ... 
} 

調用new TMyClass與調用Activator.CreateInstance<TMyClass>()通用的CreateInstance不允許參數傳遞給構造相同的效果,但你可以用非genric的CreateInstance通過他們。

public List<TMyClass> Fill(string[] ItemsPassedByParam) { 
    ... 
     myList.Add((IMyList)Activator.CreateInstance(typeof(TMyClass), item)); 
    ... 
}