【问题标题】:Set Property of Instance without Setter [duplicate]在没有 Setter 的情况下设置实例的属性 [重复]
【发布时间】: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 存储在哪里?

标签: c# .net reflection


【解决方案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;
      }
    }
    

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-07
      • 2011-05-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-25
      • 2022-12-03
      相关资源
      最近更新 更多