2012-06-02 37 views
17

Có thể nhận hoặc đặt các trường riêng tư không?Truy cập các trường riêng tư

Tôi muốn nhận được System.Guid.c. Có cách nào để truy cập vào nó hay tôi nên chỉ cần sao chép mã từ strut và làm cho các lĩnh vực công cộng?

+0

Dán riêng tư –

+0

Thay đổi nó, nhưng chỉ là System.Guid. – godzcheater

+1

có thể trùng lặp của [Tìm trường riêng tư với Reflection?] (Http://stackoverflow.com/questions/95910/find-a-private-field-with-reflection) –

Trả lời

24

Bạn có thể sử dụng phản ánh theo đề nghị của Quantic Lập trình

var guid = Guid.NewGuid(); 
var field= typeof (Guid).GetField("_c", BindingFlags.NonPublic |BindingFlags.GetField | BindingFlags.Instance); 
var value = field.GetValue(guid); 

Mặc dù nếu bạn là okay với chuyển đổi đầu tiên guid để một mảng byte, tôi có thể đề nghị:

var guid = Guid.NewGuid(); 
var c = BitConverter.ToInt16(guid.ToByteArray(), 6); 

Cách tiếp cận thứ hai tránh sử dụng sự phản chiếu.

Sửa

Bạn đề cập đến cần để có thể thiết lập giá trị là tốt, bạn vẫn có thể tránh phản ánh:

var guid = Guid.NewGuid(); 
var guidBytes = guid.ToByteArray(); 

// get value 
var c = BitConverter.ToInt16(guidBytes, 6); 

// set value 
Buffer.BlockCopy(BitConverter.GetBytes(c), 0, guidBytes, 6, sizeof(Int16)); 
var modifiedGuid = new Guid(guidBytes); 
+0

Cảm ơn, tôi nghĩ rằng nó sẽ được sử dụng đầu tiên, trừ khi có một tiêu cực để sử dụng sự phản ánh? – godzcheater

+3

@godzcheater - như đã đề cập bởi drf, sử dụng phản ánh để truy cập vào các thành viên riêng tư thường là thực hành không tốt. Bạn đang sử dụng nội bộ của một lớp để truy cập dữ liệu. Trường hợp có thể bạn nên luôn luôn cố gắng để dính vào api công cộng. Sự phản ánh của các thành viên tư nhân sẽ đòi hỏi một môi trường tin tưởng đầy đủ và có khả năng trở thành mã giòn vì nội bộ của lớp có thể thay đổi theo thời gian. –

6

Bạn nên thử System.Reflection. Dưới đây là một ví dụ:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Reflection; 

namespace AccessPrivateField 
{ 
    class foo 
    { 
     public foo(string str) 
     { 
      this.str = str; 
     } 
     private string str; 
     public string Get() 
     { 
      return this.str; 
     } 
    } 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      foo bar = new foo("hello"); 
      Console.WriteLine(bar.Get()); 
      typeof(foo).GetField("str", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(bar, "changed"); 
      Console.WriteLine(bar.Get()); 
      //output: 
      //hello 
      //changed 
     } 
    } 
} 
+1

Chỉ cần lưu ý rằng nếu bạn đang chạy Silverlight, bạn sẽ không thể truy cập các thành viên riêng tư. Bạn đã không chỉ định rằng bạn đã, nhưng chỉ trong trường hợp. –

+0

Tại sao không? Bạn có nghĩa là bạn không thể truy cập dữ liệu nội bộ của Silverlight, hoặc bạn không thể làm điều đó chút nào khi dưới Silverlight? –

+2

Với Silverlight, thời gian chạy ngăn bạn truy cập dữ liệu ngoài công khai thông qua phản chiếu vì đây là vấn đề bảo mật. Ví dụ: một số mã I/O của tệp trong thời gian chạy, nhưng bạn thường có thể truy cập nó thông qua các phương tiện đặc biệt, được quản lý không vi phạm các mối quan ngại về bảo mật. Nếu bạn có thể sử dụng sự phản chiếu để giảm xuống mức độ nặng nề của tệp I/O ẩn, thì chỉ cần duyệt đến trang Silverlight độc hại mới có thể xóa/đọc các tệp máy tính của bạn theo ý muốn. –

3

Trong khi nó có thể làm điều này với suy nghĩ, nó có thể được dễ dàng hơn chỉ cần truy xuất c từ System.Guid.ToByteArray().

byte[] guid = guid.ToByteArray(); 
short c = (short)((guid[7] << 8) | guid[6]); 

Vì phương pháp này sử dụng các phương pháp công khai và được tài liệu nên ít có thể thay đổi giữa các phiên bản. (Nói chung, dựa vào chi tiết thực hiện riêng nên tránh, vì những chi tiết này có thể thay đổi từ phiên bản lên phiên bản.)

+0

Cảm ơn người đàn ông, nhưng tôi cần phải có thể thiết lập giá trị là tốt. – godzcheater

1

Bạn có thể có một phương pháp mở rộng để có được bất kỳ lĩnh vực tư nhân của bất kỳ loại:

public static T GetFieldValue<T>(this object obj, string name) { 
    var field = obj.GetType().GetField(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); 
    return (T)field?.GetValue(obj); 
} 

Và sau đó truy cập một trường riêng thuộc loại tùy ý:

Guid id = Guid.NewGuid(); 
Int16 c = id.GetFieldValue<Int16>("_c"); 
Các vấn đề liên quan