设置实例 属性 不带 Setter

Set Property of Instance without Setter

假设我有一个 class 和一个如下所示的界面:

[Serializable]
public class MyClass : IClass
{
   public int Prop => 42;
}

public interface IClass
{
   int Prop { get; }
}

如您所见,没有 Setter。但我希望使用反射来更改 Prop 属性 但我似乎做不到。这是我目前拥有的:

var property = typeof(MyClass).GetProperty("Prop", BindingFlags.Instance | BindingFlags.Public);
property.SetValue(instaneOfClass, 31);

我不断收到此错误:System.ArgumentException: Property set method not found.

这行不通吗?如何在不使用 setter 的情况下设置 属性?

自动实现的属性具有名为 <PropName>k__BackingField 的支持字段。

在您的情况下,您将像这样访问此支持字段:

var property = typeof(MyClass).GetField("<Prop>k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic);
property.SetValue(instanceOfClass, 31);

请注意,我调用 GetField() 而不是 GetProperty(),并使用 BindingFlags.NonPublic 而不是 BindingFlags.Public,因为支持字段是私有的。

但是,由于这是一个表达式主体成员(lambda 语法),因此不会生成支持字段。 getter 不依赖于另一个成员,而是 getter returns 给定表达式的结果,编译器不需要生成支持字段。

使用显式 getter 实现您的 属性 将生成一个支持字段,上面的代码将起作用。

public class MyClass : IClass
{
   public int Prop { get; } = 42;
}

如果您指定 getter,您将拥有一个包含 属性 名称的编译器生成字段。然后可以使用反射(GetFields,SetValue)修改这个字段的值:

public class Foo        {
        public Foo() => Bar = 42;
        public int Bar { get; }        

        static void Main()  {
           var f = new Foo();
           Console.WriteLine(f.Bar); // ==> 42;
           f.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic).First(x => x.Name.Contains("Bar")).SetValue(f, 43);
           Console.WriteLine(f.Bar); // ==> 43;
  }
}

它不适用于您示例中的计算 属性。