2010-09-14 79 views
15

可能嗎?用反射或其他方式?用反射改變只讀屬性

+5

ELODIE:這是可能的,但* *不要這樣做**! – Gabe 2010-09-14 05:56:05

+0

你是否試圖改變一個屬性的返回值只有getter或只讀屬性的值(像'private readonly int primitiveValue = 1;')? – Elisha 2010-09-14 06:09:32

+0

嗨Éodie,你可以要求更多的信息,或接受答案? – 2011-01-07 11:08:33

回答

13

正如其他人所說,如果您需要這樣做,您將面臨一個設計問題。現在,如果你想知道是否有可能只是爲了知道,或者如果世界上沒有別的辦法可以做到這一點,那麼確實有可能,在非常小的helper library和擴展方法的幫助下。

考慮下面的代碼:

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"); 

使用此代碼,你可以得到一個屬性的支持字段只有財產,並分配一個新值支持字段。您可以閱讀有關implementation的更多詳細信息。

另外請注意,它僅適用於簡單的屬性,如:

public int Age { get { return age; } } 

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

public double Velocity { get; private set; } 

如果你有一個自定義代碼的複雜性,支持字段解析器將失敗。

0

它取決於屬性。如果它是一個計算屬性 - 不,除非你知道它是基於什麼。如果它只是一個私人領域的訪問者,那麼你可以嘗試修改該領域。然而,一般來說,這是一個非常糟糕的主意,因爲您可能不知道這會造成什麼樣的副作用。

0
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); 
9

作爲一個非常骯髒的解決方法自動生成的只讀屬性:

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"); 

PS:當你正在使用.NET版本< 4.6您可能需要更改一些代碼才能工作。 享受!

7

西蒙·馬特斯答案另一種是

假設你有:

public class MyClass 
{ 
    public int MyNumber {get;} 
} 

,如果你能做到這一點的測試目的:

var field = typeof(MyClass).GetField("<MyNumber>k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic); 
field.SetValue(anIstanceOfMyClass, 3);