Instantiating generic types at runtime using reflection
Emanuel Vintila

Emanuel Vintila @emanuelvintila

About: Author of, and at https://reflection.to a blog about using reflection in different programming languages.

Joined:
Oct 24, 2018

Instantiating generic types at runtime using reflection

Publish Date: Jun 9 '19
6 0

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.

Comments 0 total

    Add comment