2010-08-19 56 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)); 
    ... 
}