2013-06-14 21 views
7

Tôi sử dụng protobuf-net để tuần tự hóa/deserialize dữ liệu của tôi.Các trường chỉ đọc protobuf-net xử lý như thế nào?

Tôi có một số lớp học khá đơn giản, do đó, đó không phải là vấn đề thực sự.

Theo như tôi biết, protobuf-net sử dụng thế hệ IL để tạo mã tuần tự hóa/deserialization. Trong khi tôi có các lĩnh vực chỉ đọc trong mô hình của mình, tôi tự hỏi làm thế nào để viết cho một lĩnh vực như vậy với IL? Tôi rõ ràng có thể thấy nó hoạt động tốt, nhưng tôi không biết tại sao ...

Tôi đã cố gắng để theo dõi nó trong mã, nhưng nó là một chút quá phức tạp.

Cố gắng tự tạo mã như vậy luôn dẫn đến lỗi xác thực IL.

Trả lời

7

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ể.

+0

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. –

+0

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. –

+0

@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ị –

3

Vì tôi khá quan tâm đến cuộc thảo luận này, tôi đã thử mã ví dụ của Marc Gravell và ... nó ném VerificationException trên MS .NET 4.0.

tôi đã quản lý để làm cho nó hoạt nhưng tôi cần thiết để sử dụng DynamicMethod constructor với owner tham số thiết lập để field.DeclaringType ngay cả trong trường hợp i lĩnh vực công cộng. SkipVisibility tham số có vẻ là thừa trong trường hợp này.

PS. Tôi tin rằng mục này phải là một bình luận, nhưng do thiếu đại diện tôi không thể bình luận câu trả lời của người khác.

+0

Vâng, tôi đã không chạy mã của Marc, chỉ phân tích nó, nhưng điểm có vẻ là hợp lệ. –

Các vấn đề liên quan