2012-06-02 10 views
17

È possibile ottenere o impostare campi privati?Accesso ai campi privati ​​

Voglio ottenere System.Guid.c. C'è un modo per accedervi o dovrei semplicemente copiare il codice dal puntone e rendere pubblici i campi?

+0

la sua una pasta privato –

+0

cambiato, ma il suo solo System.Guid comunque. – godzcheater

+1

possibile duplicato di [Trova un campo privato con Reflection?] (Http://stackoverflow.com/questions/95910/find-a-private-field-with-reflection) –

risposta

24

È possibile utilizzare la riflessione, come suggerito da Quantic programmazione

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

Anche se si sta bene con convertendo prima il GUID a un array di byte, potrei suggerire:

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

Quest'ultimo approccio evita l'uso della riflessione.

Modifica

Lei parla di bisogno di essere in grado di impostare il valore come bene, si può ancora evitare la riflessione:

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

Grazie, penso che userà il primo a meno che non ci sia un negativo nell'usare il riflesso? – godzcheater

+3

@godzcheater - come menzionato da drf, l'uso della riflessione per accedere ai membri privati ​​è in genere una cattiva pratica. Stai utilizzando i componenti interni di una classe per accedere ai dati. Ove possibile, dovresti sempre provare ad aderire alla api pubblica. La riflessione dei membri privati ​​richiederà un ambiente di fiducia completo e potrebbe essere un codice fragile in quanto gli interni della classe potrebbero cambiare nel tempo. –

6

Si consiglia di provare System.Reflection. Ecco un esempio:

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

Tieni presente che se esegui Silverlight, non sarà in grado di accedere ai membri privati. Non hai specificato che lo eri, ma per ogni evenienza. –

+0

Perché no? Vuoi dire che non puoi accedere ai dati interni di Silverlight, o non puoi farlo affatto quando sei in Silverlight? –

+2

Con Silverlight, il runtime impedisce di accedere a dati non pubblici tramite la riflessione poiché si tratta di un problema di sicurezza. Ad esempio, alcuni dei codici I/O del file si trovano nel runtime, ma normalmente è possibile accedervi solo tramite mezzi speciali e gestiti che non violano i problemi di sicurezza. Se si potesse usare la riflessione per arrivare al nocciolo della I/O di file nascosti, allora semplicemente sfogliando una pagina Silverlight dannosa si potrebbero cancellare/leggere i file del computer a piacimento. –

3

Mentre è possibile fare questo con la riflessione, può essere più facile per recuperare semplicemente c da System.Guid.ToByteArray().

Poiché questo approccio utilizza metodi pubblici e documentati, è meno soggetto a modifiche tra le versioni. (In generale, basandosi su dettagli di implementazione privati ​​deve essere evitato, dal momento che questi dettagli possono cambiare da versione a versione.)

+0

Grazie amico, ma ho bisogno di essere in grado di impostare il valore pure. – godzcheater

1

si può avere un metodo di estensione per ottenere qualsiasi campo privato di qualsiasi tipo:

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

e poi accedere a un campo privato di un tipo arbitrario:

Guid id = Guid.NewGuid(); 
Int16 c = id.GetFieldValue<Int16>("_c");