Home All Groups Group Topic Archive Search About

How to define Type T for List<T> at runtime

Author
13 Jun 2006 2:19 PM
Webbert
I am looking for a way to do something similar to

public void CreateList()
{
    Type[] dataTypes =
    {   
        typeof(int),                            typeof(string)
    };

    Dictionary<string, object> mylist = new Dictionary<string, object>();

    foreach ( Type y in dataTypes )
    {
        mylist.Add( y.Name, new List<y>() );
    }
}

For reference, I   ** WILL NOT **  be using the System.Data types.  I will
be using custom classes.

Thanks,
Dave

Author
13 Jun 2006 2:33 PM
Carl Daniel [VC++ MVP]
Webbert wrote:
Show quote
> I am looking for a way to do something similar to
>
> public void CreateList()
> {
> Type[] dataTypes =
> {
> typeof(int), typeof(string)
> };
>
> Dictionary<string, object> mylist = new Dictionary<string, object>();
>
> foreach ( Type y in dataTypes )
> {
> mylist.Add( y.Name, new List<y>() );
> }
> }
>
> For reference, I   ** WILL NOT **  be using the System.Data types.  I
> will be using custom classes.
>
> Thanks,
> Dave
Author
13 Jun 2006 2:34 PM
Carl Daniel [VC++ MVP]
Webbert wrote:
Show quote
> I am looking for a way to do something similar to
>
> public void CreateList()
> {
> Type[] dataTypes =
> {
> typeof(int), typeof(string)
> };
>
> Dictionary<string, object> mylist = new Dictionary<string, object>();
>
> foreach ( Type y in dataTypes )
> {
> mylist.Add( y.Name, new List<y>() );
> }
> }

Take a look at System.Type.MakeGenericType to create a concrete Type from an
unspecialized generic type.

-cd
Author
13 Jun 2006 4:06 PM
Webbert
Using your suggestion of MakeGenericType, I came up with the following demo. 
While this works, is it necessarily the best/correct way to do it?

Thanks,
Dave

==================

using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Reflection;

namespace ConsoleApplication1
{
    class Program
    {
        Dictionary<string, object> mylist = new Dictionary<string, object>();
        private List<object> sampleData = new List<object>();

        private Type[] dataTypes =
        {   
            typeof(int),                       
            typeof(string)
        };

        static void Main( string[] args )
        {
            Program p = new Program();
            p.CreateList();
            p.FillList();
            p.DiplayList();

            Console.Out.WriteLine( "\n\nPress enter to continue..." );
            Console.In.ReadLine();
        }


        public Program()
        {
            sampleData.Add( 1 );
            sampleData.Add( "Hello" );
            sampleData.Add( 2 );
            sampleData.Add( "World" );
        }

        public void CreateList()
        {
            foreach ( Type type in dataTypes )
            {
                Type newList = typeof( List<> ).MakeGenericType( type );

                BindingFlags internalFlags =
                    BindingFlags.CreateInstance |
                    BindingFlags.Public |
                    BindingFlags.Instance;

                object instance = Activator.CreateInstance(
                    newList, internalFlags, null, null, null, null );

                mylist.Add( type.Name, instance );
            }
        }

        public void FillList()
        {
            Type listType;
            IList list;

            foreach ( object data in sampleData )
            {
                listType = data.GetType();

                list = mylist[listType.Name] as IList;
                if ( list != null )
                {
                    list.Add( data );
                }
            }
        }

        public void DiplayList()
        {
            foreach ( string keys in mylist.Keys )
            {
                IList list = mylist[keys] as IList;
                foreach ( object data in list )
                {
                    Console.Out.WriteLine( data.ToString() );
                }
            }
        }
    }
}
Author
14 Jun 2006 12:24 AM
Carl Daniel [VC++ MVP]
Webbert wrote:
> Using your suggestion of MakeGenericType, I came up with the
> following demo. While this works, is it necessarily the best/correct
> way to do it?

It's the right way to create instantiations of a generic type at runtime.

The question I'd have is why go to the trouble to create strongly typed
lists when you're only ever accessing them in weakly typed way?  You could
just use System.Collections.ArrayList everywhere and have significantly
simpler (although slightly less efficient) code.

Of course, if there's some other aspect to the real problem you're trying to
solve that benefits from having strongly typed containers, then there's
nothing wrong with this approach.

-cd
Author
14 Jun 2006 11:45 AM
Webbert
I am doing a 2-way transformation between a 3rd party xml schema and my
system.  Everything in their schema at the top level is optional which
basically turns into an object[].  With that in mind, I will have to iterate
over my list and put everything back into the object[].  So, I am providing 2
methods to work with.

One to iterate over an array of object types Type[] aTypes = {
typeof(string) ... }
foreach ( Type xyz in aTypes )
{
    IList  myvar = RetrieveList(xyz);
}

public IList RetrieveList( Type type )
{
    return ( mylist[type.Name] as IList );
}

And one to use for tighter typing.

public List<T> RetrieveList<T>()
{
    return ( mylist[typeof( T ).Name] as List<T> );
}

public List<Address> Address
{
    get { return ( RetrieveList<Address>() ); }
}


I provided the first method because, to the best of my knowledge, I am
restricted from doing something like:
foreach ( Type xyz in aTypes )
{
    List<xyz> myvar = RetrieveList<xyz>();
}


Thanks for your assistance.


Dave




Show quote
"Carl Daniel [VC++ MVP]" wrote:

> Webbert wrote:
> > Using your suggestion of MakeGenericType, I came up with the
> > following demo. While this works, is it necessarily the best/correct
> > way to do it?
>
> It's the right way to create instantiations of a generic type at runtime.
>
> The question I'd have is why go to the trouble to create strongly typed
> lists when you're only ever accessing them in weakly typed way?  You could
> just use System.Collections.ArrayList everywhere and have significantly
> simpler (although slightly less efficient) code.
>
> Of course, if there's some other aspect to the real problem you're trying to
> solve that benefits from having strongly typed containers, then there's
> nothing wrong with this approach.
>
> -cd
>
>
>
Author
14 Jun 2006 1:59 PM
Carl Daniel [VC++ MVP]
Webbert wrote:
> I provided the first method because, to the best of my knowledge, I am
> restricted from doing something like:
> foreach ( Type xyz in aTypes )
> {
> List<xyz> myvar = RetrieveList<xyz>();
> }

Yep, you're right - the ty pe parameters to a generic type must be
compile-time constants, otherwise you have to go through
Type.MakeGenericType().

-cd

AddThis Social Bookmark Button