简体   繁体   English

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

[英]Having trouble with Generics in this .NET code

i'm trying to make a mixed collection of Types. 我正在尝试制作混合类型的集合。 I know the types at the start.. but I can't seem to figure out the syntax to make the collection, etc. 我知道一开始的类型..但我似乎无法弄清楚制作集合的语法等。

eg. 例如。

....
// 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.
}

Does this mane sense? 这鬃毛有意义吗? Is this possible? 这可能吗?

Okay, now that I think I know what you want, it would look something like this: 好吧,既然我认为我知道你想要什么,它看起来像这样:

// 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)];
}

See this blog post for a similar example. 有关类似示例,请参阅此博客文章

Note that basically you're trying to represent something which generics simply can't handle, in terms of the internal dictionary type... and the first form of SomeTypeData can't be statically typed either... because that means knowing the type at compile time when we'll only actually be given it at execution time . 请注意,基本上你试图用内部字典类型表示泛型根本无法处理的东西......并且SomeTypeData的第一种形式也不能静态输入...因为这意味着知道类型在编译时 ,我们实际上只会在执行时给它。

It looks to me like you're trying to create some kind of instance repository; 在我看来,你正在尝试创建某种实例存储库; a class that stores a list of instances of a given type. 存储给定类型的实例列表的类。

Here's an example implementation. 这是一个示例实现。 I've included both a generic and non-generic version of the SomeTypeData method: 我已经包含了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;
    }
}

Below is a usage example: 以下是一个用法示例:

Generic: 通用:

        InstanceRepository repository = new InstanceRepository();

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

        listOfCats.Add(new Cat());

        Cat firstCat = listOfCats[0];

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

Non-Generic: 非通用:

        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);

I'm not sure I fully understand you're question, but if you already have an IEnumerable<Type> which contains an enumeration of Type objects, then why not just use that to initialize some type of Collection (such as List<Type> )? 我不确定我是否完全理解你的问题,但是如果你已经有一个包含Type对象枚举的IEnumerable<Type> ,那么为什么不用它来初始化某种类型的Collection(比如List<Type> )?

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

        return collection;
    }

I guess you want something like 我想你想要的东西

_dict[typeof(Cat)]=new List<Cat>();
_dict[typeof(Dog)]=new List<Dog>();

only programatically based on given types? 仅以编程方式基于给定类型?

Something like this should work: 这样的事情应该有效:

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>();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM