【问题标题】:Set readonly property value through reflection通过反射设置只读属性值
【发布时间】:2018-02-07 21:04:59
【问题描述】:

我需要修改一个只有“get”选项的属性值。我发现了一些使用 GetField 的技巧,但我没有成功。

见下方代码:

namespace ConsoleApplication1
{
  abstract class Test
  {
    private int testValue;
    protected int TestValue {
        get { return testValue; }
    }
  }
  class Myclass : Test
  {
    public Myclass(): base(){}
  }  

  class Program
  {
    static void Main(string[] args)
    {
      Myclass test = new Myclass();

      var field = typeof(Myclass).GetField("<TestValue>k__BackingField", BindingFlags.NonPublic | BindingFlags.Instance);
      field.SetValue(test, 3);

    }
  }
}

实际上,我想将“TestValue”设置为 3,但它不起作用。我可能做错了什么。

【问题讨论】:

  • 显而易见的问题是...为什么?是的,你可能会得到字段(检查绑定标志和确切名称),但这是一个讨厌的实现细节,可能会随着下一次构建而改变!您拥有该代码吗?将 setter 公开。你没有那个代码?发布一个问题,询问如何规避这个问题(当然还有一个相关的例子)。顺便说一句,这是假设代码的问题...在您的示例中,它是 testValue 而不是 &lt;TestValue&gt;k_BackingField
  • 你不能为原型添加一个setter然后删除它吗?
  • “它不工作” - 阅读 How to Ask 并解释它到底是如何不工作的以及你试图让它工作的原因。
  • @SpacemanSpiff 不,这根本不是这里要问的。

标签: c#


【解决方案1】:

您可以检索Test 类的字段信息,并使用它来设置派生类实例的值,如下所示:

var field = typeof(Test).GetField("testValue", BindingFlags.NonPublic | BindingFlags.Instance);
field.SetValue(test, 3);

【讨论】:

  • 感谢您的提示,它可以工作,但如果我只有一个没有任何字段的“Get”属性,它就无法工作。你有什么解决办法吗?例如,就我而言,我只保护了 int TestValue { get; }
  • 忘记我的最后评论,我使用了你的提示,它解决了我的问题。谢谢。
【解决方案2】:

您发现的“技巧”依赖于自动实现的属性 (string Foo { get; }),这些属性编译为带有支持字段的属性(因此是您要查找的成员的名称)。请注意,这是非常脆弱的,因为生成的成员名称没有记录。但是,一开始就依赖反射来访问类型的成员是很脆弱的。

虽然您没有自动实现的属性,但您只需要访问该属性公开的名为 testValue 的私​​有字段。

GetField() 不处理非公共成员的继承,请参阅GetFields of derived type。此方法将对此有所帮助:

public static void Main()
{
    Myclass test = new Myclass();

    var field = GetInheritedPrivateField(test.GetType(), "testValue");

    field.SetValue(test, 3);
}

private static FieldInfo GetInheritedPrivateField(Type type, string fieldName)
{
    do
    {
        var field = type.GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Instance);

        if (field != null)
        {
            return field;
        }

        type = type.BaseType;
    } 
    while (type != null);

    return null;
}

【讨论】:

    【解决方案3】:

    您不能在没有“setter”的情况下为属性设置值。

    如果您不希望该属性被范围外的其他对象覆盖,您可以使用“私有集”作为设置器,然后您可以在范围内设置值。

    另一种方法是编写一个方法来设置您的属性的 getter 的值。即

     class Myclass : Test
      {
        public Myclass(): base(){}
    
        public void SetValue(int value) { this.testValue=value; }
      }  
    

    【讨论】:

    • 你可以,通过反思。
    • 您可以设置一个值没有 setter,例如使用构造函数
    • 看问题中的代码,除了一个小错误,他们几乎做到了。此外,如果有人指出你错了,去那个人的个人资料并拒绝他们的随机答案是一件非常幼稚的事情。
    • 那看看更好。没有 setter 就不能设置属性(我的意思是 TestValue)。但是当然你可以设置变量 testValue。 - 在否决某人之前告诉我,请仔细阅读。
    • 非编译代码和陈述不正确事实的答案绝对值得反对。
    猜你喜欢
    • 1970-01-01
    • 2021-03-27
    • 2019-02-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-08
    • 2023-03-09
    相关资源
    最近更新 更多