Emanuel 3 minutes read0 hearts

Instantiating generic types at runtime

In this post, we will see how we can instantiate generic types at runtime using reflection, and call methods on the instance with correct arguments.

Assume you want to have a List<T> dynamically created at runtime; we do not want to create a List<object> instance, we want our instance to have a runtime type of List<T>. Well, of course T will be substituted with an actual type, like string, or int, depending on a user choice.

Note: there is no Exception handling; it is beyond the scope of the post.

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

namespace Reflection
{
    public class Program
    {
        private static void Main(string[] args)
        {
            Console.WriteLine("What type do you want your items to be? ");
            string input = Console.ReadLine();
            Type type = Type.GetType(input);

            // this is called an unbound type
            Type unbound = typeof(List<>);
            // unbound.IsGenericType == true
            Type bound = unbound.MakeGenericType(type);

            // get parameterless constructor and invoke it
            object list = bound.GetConstructor(new Type[0]).Invoke(new object[0]);

            // cannot use nameof with unbound types
            // string addMethod = nameof(List<>.Add);
            // use any bound type instead
            string methodNameAdd = nameof(List<object>.Add);
            MethodInfo methodAdd = bound.GetMethod(methodNameAdd);

            while (true)
            {
                Console.Write("Insert a new value into the list: ");
                input = Console.ReadLine();
                object arg = input;
                if (type != typeof(string))
                {
                    ConstructorInfo constructor = type.GetConstructor(new[] {typeof(string)});
                    // construct the type from a string
                    if (constructor != null)
                        arg = constructor.Invoke(new object[] {input});
                    // or call the static Parse method on C# primitive types
                    else
                        arg = type
                            // get the public static Parse method that accepts a string
                            .GetMethod("Parse", 0, BindingFlags.Static | BindingFlags.Public, null,
                                new[] {typeof(string)}, null)
                            .Invoke(null, new object[] {input});
                }

                methodAdd.Invoke(list, new[] {arg});
                // display the list after adding the item
                foreach (object item in (IEnumerable) list)
                    Console.Write($"{item} ");
                Console.WriteLine();
            }
        }
    }
}

We have specified that the compile-time type of the list variable is object, but it will be assigned a List<T> that will be created using reflection.

We let the user choose what type they want their list to hold. This should be specified as a fully qualified name (e.g. System.Int32). Then we add items to the list, transforming them into the appropriate type first.

Subscribe

Liked this post? Subscribe to get emails about new posts in C#.

Similar posts