tags:

views:

148

answers:

4

Hi folks,

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?

A: 

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

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

        return collection;
    }
myermian
@myermian because i actually want strongly typed lists. not a list _of_ types... This is why i'm thinking i might need an IDictionary<type, IList<type>> , if that is possible?
Pure.Krome
No, that's not really it. Given an enumerable of types, he wants to create collections containing objects of T, where typeof(T) == type. Follow? So given `new[] { typeof(string), typeof(int), typeof(Foo) }`, he wants `ICollection<string>, ICollection<int>, ICollection<Foo>`.
Anthony Pegram
+6  A: 

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.

Jon Skeet
A: 

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>();
Arunas
+1  A: 

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:

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);
Dr. Wily's Apprentice
@Dr. Wily's Apprentice : yeah, i'm doing an instance repository (i suppose). i was calling it an inmemory repo, cause it had list instances in memory :P
Pure.Krome