Thực ra, tôi không thể truy cập vào số không thành công - ít nhất, khi tạo trong bộ nhớ.
Hãy bắt đầu đơn giản, với trường public readonly
(vì vậy, chúng tôi không vi phạm bất kỳ quy tắc truy cập nào); Nỗ lực đầu tiên của tôi là như dưới đây, và nó hoạt động tốt:
using System;
using System.Reflection;
using System.Reflection.Emit;
class Foo
{
public readonly int i;
public int I { get { return i; } }
public Foo(int i) { this.i = i; }
}
static class Program
{
static void Main()
{
var setter = CreateWriteAnyInt32Field(typeof(Foo), "i");
var foo = new Foo(123);
setter(foo, 42);
Console.WriteLine(foo.I); // 42;
}
static Action<object, int> CreateWriteAnyInt32Field(Type type, string fieldName)
{
var field = type.GetField(fieldName,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
var method = new DynamicMethod("evil", null,
new[] { typeof(object), typeof(int) });
var il = method.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Castclass, type);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Stfld, field);
il.Emit(OpCodes.Ret);
return (Action<object, int>)method.CreateDelegate(typeof(Action<object, int>));
}
}
Lần duy nhất mà nó được thú vị là nếu lĩnh vực này là private
:
private readonly int i;
Đoạn mã trên sau đó cung cấp cho các oh-so-mơ hồ :
Thao tác có thể làm mất ổn định thời gian chạy.
Nhưng chúng ta có được xung quanh đó bằng cách giả vờ rằng phương pháp này là bên trong kiểu khai báo của trường:
var method = new DynamicMethod("evil", null,
new[] { typeof(object), typeof(int) }, field.DeclaringType);
Một số kiểm tra nội bộ khác có thể được thực hiện bằng cách cho phép skipVisibility
:
var method = new DynamicMethod("evil", null,
new[] { typeof(object), typeof(int) }, field.DeclaringType, true);
Tuy nhiên, lưu ý rằng không phải tất cả điều này là có thể nếu tạo các assembly độc lập. Bạn đang nắm giữ các tiêu chuẩn cao hơn nhiều khi tạo các dll thực tế. Vì lý do này, công cụ precompiler
(để tạo trước các assembly) không thể xử lý khá nhiều kịch bản giống nhau mà mã lập trình meta trong bộ nhớ có thể.
Tôi sẽ kiểm tra ngay lập tức. Có lẽ vấn đề của tôi không liên quan chặt chẽ đến các trường chỉ đọc. Điều thú vị là mã của tôi hoạt động trên Mono và không chạy trên .NET. –
Doh. Tôi không thể cung cấp DeclaringType. Nhưng bây giờ tôi tự hỏi - tại sao nó hoạt động? Một trường chỉ đọc có thể ghi được chỉ từ hàm tạo của đối tượng không? Cảm ơn bạn đã trả lời, anyway. –
@PiotrZierhoffer rất nhiều thứ chỉ được thực thi tại trình biên dịch và đầy đủ 'PEVerify'. Cuối cùng, bạn có thể thay đổi các trường 'readonly' thông qua sự phản chiếu, và serializers/materializers thường ** hoàn toàn bỏ qua ** constructor, vì vậy nếu trường hợp đó không có cách nào gán giá trị –