C# 動態建立類別實例(Activator.CreateInstance)

假設我們有個 UserType1Dto 的 class:
    
public class UserType1Dto
{
    public int Id { get; set; }
}
    

平時要實例化物件非常簡單,直接 new 就可以建立一個實例了:
    
UserType1Dto userType1Dto = new UserType1Dto();
    

那假設我們有另一個 class 叫做 UserType2Dto ,類別名稱和 UserType1Dto 很像,但屬性不同:
    
public class UserType2Dto
{
    public int Id { get; set; }
    public string Name { get; set; }
}
    

假設還有很多類似的類別,並且有相同的命名規則,除了工廠方法以外有沒有其他方式幫我們實例化物件?經過一翻研究後發現可以透過 Activator 來動態實例化物件:
    
// 動態實例化物件
string typeName = "ConsoleAppActivatorTest.UserType1Dto"; // 需要包含 namespace 的完整名稱
Type? type = Type.GetType(typeName);
object instance = Activator.CreateInstance(type);
Console.WriteLine(instance?.GetType().FullName); // ConsoleAppActivatorTest.UserType1Dto

// 設定 id 屬性
PropertyInfo? idProperty = instance.GetType().GetProperty("Id");
idProperty?.SetValue(instance, 1);
Console.WriteLine(idProperty?.GetValue(instance));


// 轉型並取出內容
UserType1Dto user = (UserType1Dto)instance;
Console.WriteLine(user.Id); // 1
    

有建構子該如何塞入參數?
    
namespace ConsoleAppActivatorTest;

public class UserType2Dto
{
    public int Id { get; set; }
    public string Name { get; set; }

    public UserType2Dto(int id, string name)
    {
        Id = id;
        Name = name;
    }
}
    

Activator.CreateInstance 的第二個參數可以塞入 object 清單,這就是建構子的參數了。
    
string typeName = $"ConsoleAppActivatorTest.UserType2Dto";
Type? type = Type.GetType(typeName);
object[] constructorArgs = new object[] { 1, "小明" };
object instance = Activator.CreateInstance(type, constructorArgs);
Console.WriteLine(instance?.GetType().FullName); // ConsoleAppActivatorTest.UserType2Dto

// 取出所有屬性
PropertyInfo[] properties = instance.GetType().GetProperties();
foreach (PropertyInfo property in properties)
{
    Console.WriteLine($"{property.Name} = {property.GetValue(instance)}");
}

/*
Id = 1
Name = 小明
 */
    

只是需要注意建構子的參數數量要正確,不然會拋出例外:
    
Unhandled exception. System.MissingMethodException: Constructor on type 'ConsoleAppActivatorTest.UserType1Dto' not found.
   at System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture)
   at System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes)
   at System.Activator.CreateInstance(Type type, Object[] args)
   at Program.<Main>$(String[] args) in C:\Users\ruyut\Documents\RiderProject
    



參考資料:
Microsoft.Learn - Activator.CreateInstance Method

留言