C# 使用反射更改只读属性

C# 使用反射更改只读属性,c#,reflection,C#,Reflection,可能吗?使用反射或任何其他方式?这取决于属性。如果它是一个计算属性-不,除非你知道它基于什么。如果它只是私有字段的访问器,那么您可以尝试修改该字段 但是,总的来说,这是一个非常糟糕的主意,因为你可能不知道这会导致什么副作用。正如其他人所说,如果你需要这样做,你首先要面对一个设计问题。现在,如果你想知道这是否可能仅仅是为了知道,或者如果地球上没有其他方法可以做到这一点,这确实是可能的,借助于一个非常小的扩展方法 考虑以下代码: class Person { int age; st

可能吗?使用反射或任何其他方式?

这取决于属性。如果它是一个计算属性-不,除非你知道它基于什么。如果它只是私有字段的访问器,那么您可以尝试修改该字段


但是,总的来说,这是一个非常糟糕的主意,因为你可能不知道这会导致什么副作用。

正如其他人所说,如果你需要这样做,你首先要面对一个设计问题。现在,如果你想知道这是否可能仅仅是为了知道,或者如果地球上没有其他方法可以做到这一点,这确实是可能的,借助于一个非常小的扩展方法

考虑以下代码:

class Person {

    int age;
    string name;

    public int Age { get { return age; } }
    public string Name { get { return name; } }
}

// ...

using Mono.Reflection;
using System.Reflection;

// ...

Person person = new Person (27, "jb");
PropertyInfo nameProperty = typeof (Person).GetProperty ("Name");
FieldInfo nameField = nameProperty.GetBackingField ();
nameField.SetValue (person, "jbe");
使用此代码,您可以仅使用属性获取属性的支持字段,并为支持字段指定一个新值。您可以阅读更多有关该项目的详细信息

还请注意,它仅适用于简单属性,例如:

public int Age { get { return age; } }

public string Name {
    get { return name; }
    set { name = value; }
}

public double Velocity { get; private set; }

如果您具有带有自定义代码的复杂属性,则支持字段解析程序将失败。

对于自动生成的只读属性,这是一个非常棘手的解决方法:

PropertyInfo isReadOnly = typeof(System.Collections.Specialized.NameValueCollection).GetProperty("IsReadOnly", BindingFlags.Instance| BindingFlags.NonPublic);
//Remove the readonly property
isReadOnly.SetValue(param, false, null);

//.............put your code here.....

// Set readonly property
isReadOnly.SetValue(param, true, null);
class MyTestClass
{
    public string MyProperty { get; }

    public MyTestClass( string MyProperty )
    {
        this.MyProperty = MyProperty;
    }
}
您可以通过以下方式修改自动生成的支持字段:

MyTestClass MyClass = new MyTestClass( "Hello" );
FieldInfo MyWriteableField = MyClass.GetType().GetRuntimeFields().Where( a => Regex.IsMatch( a.Name, $"\\A<{nameof( MyClass.MyProperty )}>k__BackingField\\Z" ) ).FirstOrDefault();
MyWriteableField.SetValue( MyClass, "Another new value" );
MyTestClass MyClass=新的MyTestClass(“你好”);
FieldInfo MyWriteableField=MyClass.GetType().GetRuntimeFields()。其中(a=>Regex.IsMatch(a.Name,$“\\Ak\uu BackingField\\Z”)。FirstOrDefault();
设置值(MyClass,“另一个新值”);
注:当您使用.NET版本<4.6时,可能需要更改一些代码才能工作。
享受吧

Simon Mattes的备选答案是

假设你有:

public class MyClass
{
     public int MyNumber {get;}
}
如果出于测试目的:

var field = typeof(MyClass).GetField("<MyNumber>k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic);
field.SetValue(anIstanceOfMyClass, 3);
var field=typeof(MyClass).GetField(“k_ubackingfield”,BindingFlags.Instance | BindingFlags.NonPublic);
字段设置值(anIstanceOfMyClass,3);

埃洛迪:这是可能的,但不要这样做!!!您是否试图使用getter only更改属性的返回值,或者更改只读的支持字段的值(如
private readonly int primitiveValue=1;
)?您好,您可以请求更多信息,还是接受回答?@Gabe:一般来说,我同意。我不得不用它来调试一些我没有源代码的代码。当您需要强制代码执行某些操作以在调试时暴露错误行为时,这非常有用。在反序列化对象时,我需要这样做,其中一个只读属性是集合。这是你想这么做的另一个“好”理由。仅供参考,在非只读支持字段上调用反射更容易、更清晰。我已经尝试过了,但它不起作用。您要做的就是将属性设置为false,然后再设置为true。它的神奇字段名
“k_ubackingfield”
工作)