使用 Activator.CreateInstance 时设置仅限 init 的属性

Mik*_* L. 7 c# constructor properties init-only

C# 9.0 引入了仅 init 类属性功能,但在使用 Activator.CreateInstance 按类类型创建实例时无法使用它们。一个简单的例子:

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

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

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

Dav*_*d L 7

初始化属性只能在以下上下文中设置:

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

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

Person person = new Person { Name = "Bob" };
Run Code Online (Sandbox Code Playgroud)

Person person2 = new Person();
person2.Name = "test";
Person person = person;
Run Code Online (Sandbox Code Playgroud)

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

Person person = (Person)Activator.CreateInstance(typeof(Person));
    
person.GetType().GetProperty("Name").SetValue(person, "Bob");
Run Code Online (Sandbox Code Playgroud)

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

  • 反射允许您在运行时修改某些内容,而不受编译器提供的任何限制。Init 是一个编译器概念,而不是 IL 或运行时概念。因此,一旦通过编译,您就可以根据需要更改对象状态。 (2认同)