在没有 Setter 的情况下设置实例的属性 [重复]

Posted

技术标签:

【中文标题】在没有 Setter 的情况下设置实例的属性 [重复]【英文标题】:Set Property of Instance without Setter [duplicate] 【发布时间】:2021-09-22 00:51:54 【问题描述】:

假设我有一个如下所示的类和接口:

[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 的情况下设置属性?

【问题讨论】:

我将其作为先前建议答案的副本关闭,因为它已经包含文本“复杂代码”。我还编辑了答案以添加“复杂代码包括int TheAnswer => 42;,因此它也清楚地回答了这个问题。 剩下的谜团是:值 '42' 的 int 存储在哪里? 【参考方案1】:

自动实现的属性具有名为 <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 实现您的属性将生成一个支持字段,上面的代码将起作用。

public class MyClass : IClass

   public int Prop  get;  = 42;

【讨论】:

【参考方案2】:

如果您指定一个 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;
  

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

【讨论】:

以上是关于在没有 Setter 的情况下设置实例的属性 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

如何在不使用 setter 的情况下调试更新 php Trait 的实例变量

属性readwrite,readonly,assign,retain,copy,nonatomic 各是什么作用,在哪种情况下用?

7在对象内部尽量直接访问实例变量

WCF:公开只读 DataMember 属性而不设置?

getter和setter

getter和setter