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.
Top comments (0)