这是可能的:带有约束的类型的c#集合,还是泛型类型的集合?

时间:2010-06-03 20:06:44

标签: c# generics collections

我正在尝试将类型存储在集合中,以便稍后我可以实例化集合中类型的对象。但我不知道如何以最好的方式做到这一点。

到目前为止:

List<Type> list = new List<Type>();
list.Add(typeof(MyClass));
var obj = (MyClass)Activator.CreateInstance(list[0]);

我想在Type上有一些约束,或者更好的是,只是集合中的泛型类型而不是实例化的Type对象。这可能吗?

5 个答案:

答案 0 :(得分:5)

这不是通用集合约束的工作方式。

Generic constraints限制哪些类型对于实例化泛型类型是合法的。有几种不同类型的约束,但常见的约束将通用参数限制为继承或是实例给定类型,或者是实现特定接口(或接口集)的类型。

另一方面,

Type ,是一个描述应用程序或其中一个库类型信息的类。特定类型的类型不会继承或扩展Type - 而是针对每种可用类型,Type都有不同的实例。您不能使用通用约束来控制可以将Type的哪些实例添加到您的集合中。

如果没有关于如何“约束”集合中的信息的更多细节,很难说你应该采取什么样的路线。例如,如果你想做的就是确保只做存储了唯一类型(无重复),可以使用HashSet(而不是列表)来实现。但是如果你想要更专业的东西 - 比如限制可以添加到某些类型子集的Type实例,那么你可能需要实现自己的集合,并在Add / Insert方法中实现gaurd逻辑。 / p>

答案 1 :(得分:3)

在这个特殊场景中,似乎我们有一个“工厂”模式,我们会限制调用激活器的方法,例如

private readonly List<Type> _supportedTypes = new List<Type> ();
public void RegisterSupportedType<T> () where T : SomeConstraintType
{
    _supportedTypes.Add (typeof (T));
}

// if we do not know the type, but somehow know an index to type
public object Create (int supportedTypeIndex)
{
    object untyped = Activator.
        CreateInstance (_supportedTypes[supportedTypeIndex]);
    return untyped;
}

// if we know instance type\subtype (eg interface) and know an index
public T Create<T> (int supportedTypeIndex)
{
    T typed = default (T);
    object untyped = Create (supportedTypeIndex);
    if (!(untyped is T))
    {
        // throw meaningful exception :)
    }
    typed = (T)(untyped);
    return typed;
}

另一种方法是创建约束Type

public class ConstrainedType<T> 
{
    public Type Type { get; private set; }
    public ConstrainedType (Type type)
    {
        // may have this backward, would have to fact check before
        // rolling out to prod ;)
        if (!typeof (T).IsAssignableFrom (type))
        {
            // throw meaningful exception!
        }
        Type = type;
    }
}

List<ConstrainedType<SomeTypeConstraint>> list = 
    new List<ConstrainedType<SomeTypeConstraint>> ();

// will throw meaningful exception if MyClass is not 
// SomeTypeConstraint or a sub class
list.Add (new ConstrainedType (typeof (MyClass)));

SomeTypeConstraint baseType = 
    (SomeTypeConstraint)(Activator.CreateInstance(list[0].Type));

答案 2 :(得分:1)

乔,

如果您使用CodeContracts,则可能需要许多已知类型。代码分析会使用无效类型标记对集合的任何调用。

public class TypeCollection : List<Type>
{
    public TypeCollection()
    {
    }

    public new void Add(Type type)
    {
        Contract.Requires(type == typeof(string) || type == typeof(Stream));
        base.Add(type);
    }
}

public class TestCollection
{
    public void Test()
    {
        TypeCollection collection = new TypeCollection();
        // This gets compile time warning:
        collection.Add(typeof(int));
    }
}

但是,如果你事先知道这些类型,那么在枚举中指定它们并为你想要支持的类型创建创建有效枚举的集合可能更有意义。

答案 3 :(得分:0)

第一种方式(似乎很愚蠢,但它是安全的):
(在List ||实现IList上创建一个包装器)并检查.Add方法中的.Exists(item)。

答案 4 :(得分:0)

如果要实现自己的集合,可以使用泛型类型约束:

public class MyList<T> 
    where T : IMyConstraint