使用 Activator.CreateInstance 时设置仅初始化属性

Setting init-only properties when using Activator.CreateInstance

C# 9.0 引入了 init-only class 属性功能,但在通过 class 类型和 Activator.CreateInstance 创建实例时不能使用它们。一个简单的例子:

class Person
{
    public string Name { get; init; }
}

void Test()
{
    Person person = (Person)Activator.CreateInstance(typeof(Person));
    person.Name = "Bob"; // Doesn't work
}

寻找除了使用构造函数参数(太多)之外的其他解决方案。

Init 应该在对象的构造中初始化,因此您应该在构造函数中初始化它的值。你可以这样做:

(Person)Activator.CreateInstance(typeof(Person), "Bob");

注意,需要添加合适的构造函数。

class Person
{
    public Person(string name)
    {
        Name = name;
    }        

    public string Name { get; init; }
}

Init 属性只能在以下 contexts:

中设置
  • 在对象初始化期间
  • with 表达式初始化程序期间
  • 在包含或派生类型的实例构造函数内,在 thisbase
  • 在任何 属性 的 init 访问器内,在 thisbase
  • 带命名参数的内部属性用法

反过来,对象初始化只是语法糖,无需直接调用构造函数即可设置实例属性或字段,本质上是从

Person person = new Person { Name = "Bob" };

Person person2 = new Person();
person2.Name = "test";
Person person = person;

当使用 Activator.CreateInstance 时,您绕过了这个语法糖。也就是说,如果您已经在使用 Activator.CreateInstance,您可能会很乐意接受额外的反射命中。您可以简单地调用 PropertyInfo.SetValue 在对象创建后设置值:

Person person = (Person)Activator.CreateInstance(typeof(Person));
    
person.GetType().GetProperty("Name").SetValue(person, "Bob");

或者,您可以创建构造函数并将值传递给构造函数。