使用通用类型或接口的C#集合

时间:2010-08-19 15:22:00

标签: c# generics collections interface types

我有一组实现接口(MyClass1, MyClass2, MyClass3)的类(IMyClass)。

我有兴趣创建一个方法来填充和返回具有公共接口Collection.Generics.Lists<> MyClass ({{1}的对象的列表(X) }})。但是如何?

每个类都有一个构造函数List<IMyClass> MyClass ,它可以做一些与众不同的事情。所以我无法创建 BaseClass 并为所有人使用通用构造函数。

通过界面我无法做到:

X

此外,我尝试在下一个示例中使用泛型类型TMyClass,但两者都没有对我有用(尽管我对泛型类型的概念不是很深):

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!!
    }
}

我还尝试在方法中将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!! } } MyClass 的构造函数中的代码外部化,但我无法调用该方法,因为de object未初始化(没有X)。

在这些情况下,这是解决方案吗?

提前致谢!

4 个答案:

答案 0 :(得分:7)

听起来您希望Fill方法根据传入的字符串值创建List<T>,其中TIMyClass的派生。

您需要做的是将工厂函数传递给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));        
  }
}

然后在您调用Fill的地方,您可以选择使用<{1}}的派生

IMyClass

答案 1 :(得分: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));
    }
}

答案 2 :(得分: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));
    ...
}

答案 3 :(得分:1)

也许你可以在这里使用工厂模式,具体取决于你如何判断需要哪种类型。

也许你需要使用反射并调用一个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});
}