2012-06-02 14 views
17

¿Es posible obtener o establecer campos privados?Acceso a campos privados

Quiero obtener System.Guid.c. ¿Hay alguna manera de acceder a él o debería simplemente copiar el código del puntal y hacer que los campos sean públicos?

+0

su una pasta privada –

+0

lo cambió, pero su justo System.Guid de todos modos. – godzcheater

+1

posible duplicado de [¿Encontrar un campo privado con Reflection?] (Http://stackoverflow.com/questions/95910/find-a-private-field-with-reflection) –

Respuesta

24

Puede utilizar la reflexión según lo sugerido por Quantic Programación

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

Aunque si estás bien con convirtiendo en primer lugar el GUID a una matriz de bytes, lo que podría sugerir:

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

El último enfoque evita el uso de la reflexión.

Editar

usted menciona la necesidad de ser capaz de establecer el valor, así, todavía se puede evitar la reflexión:

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

Gracias, creo que usará el primero a menos que haya un uso negativo de la reflexión. – godzcheater

+3

@godzcheater - como lo menciona drf, el uso de la reflexión para acceder a miembros privados generalmente es una mala práctica. Está utilizando las partes internas de una clase para acceder a los datos. Siempre que sea posible, siempre debe intentar apegarse a la API pública. La reflexión de los miembros privados requerirá un entorno de confianza total y tiene el potencial de ser un código frágil, ya que los aspectos internos de la clase pueden cambiar con el tiempo. –

6

Deberías probar System.Reflection. He aquí un ejemplo:

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

Solo tenga en cuenta que si está ejecutando Silverlight, no podrá acceder a los miembros privados. No especificó que lo era, pero por las dudas. –

+0

¿Por qué no? ¿Quiere decir que no puede acceder a los datos internos de Silverlight o no puede hacerlo cuando está bajo Silverlight? –

+2

Con Silverlight, el tiempo de ejecución le impide acceder a datos no públicos mediante la reflexión, ya que es un problema de seguridad. Por ejemplo, parte del código de E/S del archivo está en el tiempo de ejecución, pero normalmente solo puede acceder a él a través de medios especiales y administrados que no violan las preocupaciones de seguridad. Si pudieras usar el reflejo para llegar a la esencia de la E/S de archivos ocultos, entonces con solo navegar a una página maliciosa de Silverlight podrías borrar/leer los archivos de tu computadora a voluntad. –

3

Si bien es posible hacer esto con la reflexión, puede ser más fácil simplemente recuperar c desde System.Guid.ToByteArray().

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

Dado que este enfoque utiliza métodos públicos y documentados, está menos sujeto a cambios entre versiones. (En general, basándose en los detalles de implementación privados debe ser evitado, ya que estos detalles pueden cambiar de una versión a otra.)

+0

Gracias, pero también necesito poder establecer el valor. – godzcheater

1

Usted puede tener un método de extensión para obtener cualquier campo privado de cualquier 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); 
} 

y luego acceder a un campo privado de un tipo arbitrario:

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