2010-09-14 22 views
15

Có thể không? Với sự phản ánh hay cách nào khác?Thay đổi các thuộc tính chỉ đọc với sự phản chiếu

+5

Élodie: Có thể, nhưng * * KHÔNG LÀM IT ** !!! – Gabe

+0

Bạn đang cố gắng thay đổi giá trị trả về của một thuộc tính chỉ với getter, hoặc giá trị của trường sao lưu chỉ đọc (như 'readonly int primitiveValue = 1;')? – Elisha

+0

Hi Élodie, bạn có thể yêu cầu thêm thông tin hay chấp nhận câu trả lời không? –

Trả lời

13

Như đã nêu khác, nếu bạn cần làm điều đó, bạn đang phải đối mặt với một vấn đề thiết kế để bắt đầu. Bây giờ, nếu bạn muốn biết nếu nó có thể chỉ vì lợi ích của việc biết, hoặc nếu không có cách nào khác trên trái đất để làm điều đó, nó thực sự có thể, với sự giúp đỡ của một rất nhỏ helper library và một phương pháp mở rộng.

Xét đoạn mã sau:

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

Sử dụng mã này, bạn có thể nhận được sự ủng hộ lĩnh vực của một tài sản với tài sản chỉ, và chỉ định một giá trị mới cho lĩnh vực sao lưu. Bạn có thể đọc thêm chi tiết về số implementation.

Cũng lưu ý rằng nó chỉ hoạt động đối với tài sản đơn giản, chẳng hạn như:

public int Age { get { return age; } } 

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

public double Velocity { get; private set; } 

Nếu bạn có các tính chất phức tạp với mã tùy chỉnh, resolver lĩnh vực sao lưu sẽ thất bại.

0

tùy thuộc vào thuộc tính. nếu đó là thuộc tính được tính toán - không, trừ khi bạn biết nó dựa trên cái gì. nếu đó chỉ là một người truy cập vào một trường riêng, thì bạn có thể cố gắng sửa đổi trường này. Tuy nhiên,

nói chung là một ý tưởng rất tồi, vì bạn có thể không biết tác dụng phụ nào sẽ gây ra.

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

Là một workaround rất bẩn để tự động tạo ra chỉ đọc thuộc tính:

class MyTestClass 
{ 
    public string MyProperty { get; } 

    public MyTestClass(string MyProperty) 
    { 
     this.MyProperty = MyProperty; 
    } 
} 

Bạn có thể thay đổi tự động tạo lĩnh vực sao lưu theo cách sau:

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: khi bạn đang sử dụng phiên bản .NET < 4.6 bạn có thể phải thay đổi một số mã để hoạt động. Tận hưởng!

7

Một thay thế cho Simon Mattes trả lời sẽ là

Giả sử bạn có:

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

Bạn có thể làm điều này nếu nó cho mục đích thử nghiệm:

var field = typeof(MyClass).GetField("<MyNumber>k__BackingField", BindingFlags.Instance | BindingFlags.NonPublic); 
field.SetValue(anIstanceOfMyClass, 3); 
Các vấn đề liên quan