在这个.NET代码中遇到Generics的问题

时间:2010-09-17 14:03:52

标签: c# .net generics

我正在尝试制作混合的类型集合。我知道一开始的类型..但我似乎无法弄清楚制作集合的语法等。

例如

....
// I leave the typo there, for embarrassment :(
Initialize(new []{ typeof(Cat), typeof(Dog), typeof(JohnSkeet) }); 
...

public Foo Initialize(IEnumerable<Type> types)
{
   // for each type, set up the inmemory storage.
   foreach(var type in types)
   {
       // ????
       // Create an empty list, which will only contain this 'type'
       // I'm guessing, an IDictionary<type, ICollection<type>>().. thingy ?
   }
}

public ICollection<Type> SomeTypeData(Type type)
{
    // Return the collection, for this type.
}

这种鬃毛有意义吗?这可能吗?

4 个答案:

答案 0 :(得分:6)

好的,现在我觉得我知道你想要什么,它看起来像这样:

// This can't really be *properly* statically typed
private readonly Dictionary<Type, object> typeMap = new 
    Dictionary<Type, object>();

public Foo Initialize(IEnumerable<Type> types)
{
   Type genericListType = typeof(List<>);
   foreach(var type in types)
   {
       // MakeGenericType is really badly named
       Type constructedListType = genericListType.MakeGenericType(type);
       typeMap[type] = Activator.CreateInstance(constructedListType);
   }
}

// We can't express this particularly safely either,
// although we *could* return the non-generic IList
public object SomeTypeData(Type type)
{
    return typeMap[type];
}

// This *is* statically typed, although we need to cast inside
public IList<T> SomeTypeData<T>()
{
    return (IList<T>) typeMap[typeof(T)];
}

有关类似示例,请参阅this blog post

请注意,就内部字典类型而言,基本上你试图表示泛型根本无法处理的东西......并且SomeTypeData的第一种形式也不能静态输入。因为这意味着在编译时知道类型,而我们只会在执行时实际给出它。

答案 1 :(得分:1)

在我看来,你正在尝试创建某种实例存储库;存储给定类型实例列表的类。

这是一个示例实现。我已经包含了SomeTypeData方法的泛型和非泛型版本:

public class InstanceRepository
{
    private IDictionary<Type, ICollection> _Instances = new Dictionary<Type, ICollection>();

    public ICollection SomeTypeData(Type type)
    {
        ICollection instanceList;
        if (!_Instances.TryGetValue(type, out instanceList))
        {
            // this type does not exist in our dictionary, so let's create a new empty list

            // we could do this:
            //instanceList = new List<object>();

            // but let's use reflection to make a more type-specific List<T> instance:
            instanceList = (ICollection)Activator.CreateInstance(typeof(List<>).MakeGenericType(type));

            // now add it to the dictionary
            _Instances.Add(type, instanceList);
        }
        // Return the collection, for this type.
        return instanceList;
    }

    public IList<T> SomeTypeData<T>()
    {
        Type type = typeof(T);
        ICollection instanceList;
        if (!_Instances.TryGetValue(typeof(T), out instanceList))
        {
            instanceList = new List<T>();
            _Instances.Add(type, instanceList);
        }
        // here we are assuming that all of the lists in our dictionary implement IList<T>.
        // This is a pretty safe assumption, since the dictionary is private and we know that
        // this class always creates List<T> objects to put into the dictionary.
        return (IList<T>)instanceList;
    }
}

以下是一个用法示例:

通用:

        InstanceRepository repository = new InstanceRepository();

        var listOfCats = repository.SomeTypeData<Cat>();

        listOfCats.Add(new Cat());

        Cat firstCat = listOfCats[0];

        Console.WriteLine(listOfCats.GetType().FullName);

非通用:

        InstanceRepository repository = new InstanceRepository();

        var listOfCats = (IList<Cat>)repository.SomeTypeData(typeof(Cat));

        listOfCats.Add(new Cat());

        Cat firstCat = listOfCats[0];

        Console.WriteLine(listOfCats.GetType().FullName);

答案 2 :(得分:0)

我不确定我是否完全理解你的问题,但是如果你已经有一个包含Type对象枚举的IEnumerable<Type>,那么为什么不用它来初始化某种类型的Collection(例如List<Type>)?

    public ICollection<Type> Initialize(IEnumerable<Type> types)
    {
        ICollection<Type> collection = new List<Type>(types);

        return collection;
    }

答案 3 :(得分:0)

我想你想要像

这样的东西
_dict[typeof(Cat)]=new List<Cat>();
_dict[typeof(Dog)]=new List<Dog>();

仅以编程方式基于给定类型? 这样的事情应该有效:

public void Initialize(IEnumerable<Type> types)
{
    foreach(var type in types)
    {
        var list = Activator.CreateInstance(Type.GetType("System.Collections.Generic.List`1").MakeGenericType(type));
        _cache[type] = list;
    }
}

public ICollection<T> Get<T>()
{
    object list;
    if (_cache.TryGetValue(typeof(T), out list)
    {
       return list as ICollection<T>;
    }
    else
    {
       ...
    }
}

var cats = Get<Cat>();