2013-08-05 23 views
7

Vì vậy, tôi đã gặp phải một vấn đề lạ trong khi không quan tâm và học tập phản chiếu. Tôi đang cố gắng để thay đổi một, lĩnh vực readonly tin, giống như nhìn thấy dưới đây:Không thể thay đổi trường chỉ đọc với sự phản chiếu

public class A 
{ 
    private static readonly int x; 

    public int X 
    { 
     get { return x; } 
    } 
} 

static void Main(string[] args) 
{ 
    A obj = new A(); 
    Type objType = typeof(A); 

    Console.WriteLine(obj.X); 

    FieldInfo objField = objType.GetField("x", BindingFlags.Static | BindingFlags.NonPublic); 
    objField.SetValue(null, 100); 

    Console.WriteLine(obj.X); 

    Console.ReadLine(); 
} 

Nếu tôi chạy chương trình khi nó đứng ở trên, sau đó 0 sẽ được in để an ủi mỗi lần. Tuy nhiên, nếu tôi nhận xét bản in đầu tiên, thì phần thứ hai sẽ viết ra 100.

Bất kỳ ai có thể làm sáng tỏ những gì đang xảy ra ở đây? Cảm ơn!

EDIT: Điều lạ lùng có vẻ như hoạt động trong Visual Studio 2012, nhưng không phải trong năm 2010. Theo như tôi đã tìm thấy, các cài đặt đều giống nhau trong cả hai.

CHỈNH SỬA 2: Hoạt động khi xây dựng với mục tiêu nền tảng x64 và không hoạt động với x86. Đoán câu hỏi mới là: tại sao vậy?

CHỈNH SỬA 3: So sánh các phiên bản x64 và x86 để tháo gỡ; dường như có một số nội tuyến đang diễn ra trong phiên bản x86.

CHỈNH SỬA 4: Okey, nghĩ Tôi đã tìm ra điều gì đang xảy ra, sắp xếp. Tôi không nghĩ rằng tài sản trong lớp A được gạch chân là vấn đề. Tôi tin rằng khi đến lúc đọc thuộc tính lần thứ hai trong phương thức chính, cuộc gọi thuộc tính được tối ưu hóa (trường sao lưu phải là chỉ đọc, giá trị phải giống nhau) và giá trị cũ được sử dụng lại. Đó là lý thuyết của tôi ít nhất.

+0

thats vì lần đầu tiên bạn in bạn đang gọi nó gán giá trị mặc định là 0 và sau đó là 0, nếu bạn nhận xét đầu tiên, thì bạn chỉ định giá trị 100 và sau đó in giá trị của nó. – terrybozzio

+1

* Gọi Marc Gravel, gọi Marc Gravel * – Will

+0

Vì trường này được đánh dấu là 'readonly', JIT có thể là nội tuyến của' X' getter. – Romoku

Trả lời

6

Các JIT là nội tuyến getter:

Sử dụng MethodImplAttribute trên getter để đề nghị JIT không inline tài sản. Điều này sẽ không ngăn cản giá trị của x từ việc được nội tuyến, nhưng việc xóa readonly sẽ tạo ra kết quả mong muốn.

public class A 
{ 
    private static int x; 

    public int X 
    { 
     [MethodImpl(MethodImplOptions.NoInlining)] 
     get { return x; } 
    } 
} 

Bây giờ đầu ra sẽ là:

0 
100 

Xem: Does C# inline properties?

Một workaround đơn giản là sử dụng nguyên nullable (int?) kiểu giá trị.

public class A 
{ 
    private static readonly int? x; 

    public int X 
    { 
     get 
     { 
      return x ?? 0; 
     } 
    } 
} 

x sẽ không nhận được inlined kể từ khi CLR sẽ cần phải kiểm tra xem giá trị của x là một dàn diễn viên hợp lệ để int.

+0

Bạn có thể thấy các kết quả khác nhau khi bạn biên dịch một bản dựng gỡ lỗi thay vì bản phát hành ngay cả sau khi thực hiện thay đổi đó. Tôi cảm thấy chắc chắn rằng nó phải là một cái gì đó * để làm với jitter, mặc dù. –

+1

Tôi vẫn nhận được kết quả tương tự; cả hai đều có nguồn gốc từ MarshalByRefObject và với thuộc tính. –

+0

Mã trên vẫn tái tạo "vấn đề" trong điều kiện được chỉ định trong đoạn EDIT của câu hỏi, vì vậy 'NoInlining' trong thuộc tính của' get' accessor dường như không đủ. –

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