[C#] Dynamically Calling Constructors and Creating Instances with Type.GetConstructor and Invoke

In C#, we typically use the new ClassName(...) syntax to create instances. However, in scenarios such as plugin systems or DI (Dependency Injection) container implementations, the type to be instantiated might not be determined until runtime.

In such cases, by combining the Reflection features Type.GetConstructor and ConstructorInfo.Invoke, you can specify the argument type signature, call a specific constructor, and create an object dynamically.

目次

Dynamic Invocation of Constructors with Specific Arguments

The following sample code demonstrates how to identify and instantiate a constructor for a Product class that takes two arguments: an int (ID) and a string (Name).

Sample Code

using System;
using System.Reflection;

public class Program
{
    public static void Main()
    {
        // 1. Get type information of the class to instantiate
        // In reality, you might get this from a string like Type.GetType("Namespace.Product")
        Type targetType = typeof(Product);

        Console.WriteLine($"Target Type: {targetType.Name}");

        // 2. Define the array of argument types for the constructor we want to call
        // Here we target public Product(int id, string name)
        Type[] constructorArgsTypes = new Type[] 
        { 
            typeof(int), 
            typeof(string) 
        };

        // 3. Get constructor info matching the argument types
        ConstructorInfo ctorInfo = targetType.GetConstructor(constructorArgsTypes);

        if (ctorInfo != null)
        {
            // 4. Prepare actual arguments as an object array and execute the constructor (Invoke)
            object[] executionArgs = new object[] { 1001, "Gaming Keyboard" };
            
            // The return value of Invoke is object type, so cast if necessary
            var createdInstance = ctorInfo.Invoke(executionArgs);

            // Check result
            Console.WriteLine("Instance creation successful.");
            Console.WriteLine($"Created Object: {createdInstance}");
        }
        else
        {
            Console.WriteLine("Constructor with the specified signature was not found.");
        }
    }
}

// Sample Product Class
public class Product
{
    public int Id { get; }
    public string Name { get; }

    // Target Constructor
    public Product(int id, string name)
    {
        Id = id;
        Name = name;
    }

    // Parameterless Constructor (Not used this time)
    public Product()
    {
        Id = 0;
        Name = "Unknown";
    }

    public override string ToString()
    {
        return $"[Product] ID:{Id}, Name:{Name}";
    }
}

Explanation and Technical Points

1. Type.GetConstructor Method

Classes can have multiple constructors (overloads). Therefore, you must pass a Type array to the GetConstructor method to indicate “which combination of arguments (signature) you want to retrieve.”

  • For parameterless constructors: Pass Type.EmptyTypes.
  • If no match is found: It returns null.

2. ConstructorInfo.Invoke Method

This method uses the obtained constructor information to actually create the object. You pass an object array containing the actual values in the order defined by the constructor definition. It returns the newly created instance.

3. Difference from Activator.CreateInstance

Activator.CreateInstance also exists as a simple way to create instances dynamically.

  • Activator.CreateInstance: Convenient, but it infers the appropriate constructor internally, making strict control of overload resolution difficult in some cases.
  • ConstructorInfo.Invoke: Since you perform a strict signature check with GetConstructor beforehand, it is suitable when you want to call a specific constructor precisely or when you prioritize performance by caching metadata.
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次