c#

¿Cómo obtener el valor del campo privado en C#?



(9)

Me encontré con un problema que necesito para acceder al campo privado de una clase. Por ejemplo:

class MyClass { private string someString; public MyClass( string someStringValue ) { someString = someStringValue; } }

¿Cómo puedo obtener el valor de someString fuera de MyClass?

Actualizar:

Lo sentimos, no puedo usar la propiedad aquí ya que el código de producción real está protegido. Soy un QA / Dev, necesito una forma de obtener esos datos privados para escribir la Prueba de aceptación del usuario. Así que no puedo cambiar el código de producción. ¿Puede usted ayudar?


Además de la respuesta de @dcp, esto puede ser mucho más fácil convirtiéndolo en función genérica ...

internal static T GetInstanceField<T>(object instance, string fieldName) { BindingFlags bindFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static; FieldInfo field = type.GetField(fieldName, bindFlags); return field.GetValue(instance); }


Aquí hay una versión genérica que funciona tan limpia como puedo conseguirla.

private static object GetInstanceField<T>(T instance, string fieldName) { BindingFlags bindFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static; FieldInfo field = typeof(T).GetField(fieldName, bindFlags); return field.GetValue(instance); }

uso

var str = (string)GetInstanceField(instance, "someString");


Como han dicho otros, ya que el campo es privado, no debe intentar obtenerlo con el código normal. El único momento en que esto es aceptable es durante la prueba de unidad, e incluso entonces necesita una buena razón para hacerlo (como establecer una variable privada en nula para que el código en un bloque de excepción sea afectado y pueda ser probado).

Podría usar algo como el método a continuación para obtener el campo:

/// <summary> /// Uses reflection to get the field value from an object. /// </summary> /// /// <param name="type">The instance type.</param> /// <param name="instance">The instance object.</param> /// <param name="fieldName">The field''s name which is to be fetched.</param> /// /// <returns>The field value from the object.</returns> internal static object GetInstanceField(Type type, object instance, string fieldName) { BindingFlags bindFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static; FieldInfo field = type.GetField(fieldName, bindFlags); return field.GetValue(instance); }

Así que podrías llamar a esto como:

string str = GetInstanceField(typeof(YourClass), instance, "someString") as string;

De nuevo, esto no debe usarse en la mayoría de los casos.


Hazlo una propiedad pública

public string SomeString {get; private set;}

Esa declaración de propiedad permitirá que cualquier clase externa lea la variable pero no la modifique (de ahí el "setter" privado).

EDIT: Acabo de ver tu comentario en la otra respuesta. Vas a tener que usar Relection para llegar a una variable privada como esa. Y como en otra respuesta sugerida, asegúrese de tener cuidado con los programadores con sticks;). Dicho esto, busque en Google algo como "encontrar el valor de la propiedad con la reflexión C #".


No puedes, y no estás destinado a hacerlo. Es privado Si esta es la clase de otra persona, entonces claramente no quieren que tengas acceso a ese campo. El hecho de que sea privado les permite cambiar la implementación más adelante; pueden terminar con ese valor como parte de otra variable, o cambiar su nombre, o posiblemente desaparecer por completo si ya no es necesario para implementar la API pública.

Si se trata de su propia clase y está seguro de que desea que otras personas puedan acceder a ella, expóngala con una propiedad:

public string SomeString { get { return someString; } }

EDITAR: Habiendo visto sus comentarios, puede acceder a los campos privados con una reflexión ... pero para una prueba de aceptación no debería hacerlo. Deberías estar probando la API pública. Para las pruebas unitarias tiene sentido doblar las reglas a veces, y tratar a la clase como una "caja blanca" en lugar de hacer pruebas de "caja negra", pero para las pruebas de aceptación definitivamente me quedaría con la API pública.

Si esto no funciona, le sugiero que hable con los desarrolladores del código de producción: explique por qué desea acceder y pídales que lo expongan a través de una propiedad. Podrían convertirlo en una propiedad interna, y usar [InternalsVisibleTo] para obtener acceso a ella en el ensamblaje de prueba. Personalmente preferiría esto a usar la reflexión; de lo contrario, si el código de producción cambia de una manera perfectamente válida, sus pruebas fallarán cuando no deberían hacerlo.


Puede utilizar este método de extensión.

public static class Extensions { public static object GetFieldValue(this object instance, string fieldName) { const BindingFlags bindFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static; var field = instance.GetType().GetField(fieldName, bindFlags); return field == null ? null : field.GetValue(instance); } }


Si lo está utilizando para pruebas unitarias, implementé una versión genérica de la respuesta de @dcp que proporciona los siguientes extras:

  • Afirma si el campo existe
  • Afirma si el valor es de tipo "T".
  • Convierte el valor al tipo "T".

Código:

private const BindingFlags BindFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static; /// <summary> /// Uses reflection to get the field value from an object. /// </summary> /// <param name="type">The instance type.</param> /// <param name="instance">The instance object.</param> /// <param name="fieldName">The field''s name which is to be fetched.</param> /// <returns>An instance of <see cref="T"/>.</returns> internal static T GetInstanceField<T>(Type type, object instance, string fieldName) { var field = type.GetField(fieldName, BindFlags); Assert.IsNotNull(field, string.Format("The field with name ''{0}'' does not exist in type ''{1}''.", fieldName, type)); var value = field.GetValue(instance); Assert.IsInstanceOfType(value, typeof(T), string.Format("The value of the field ''{0}'' is not of type ''{1}''", fieldName, typeof(T))); return (T)value; }


Si se trata de una clase y desea proporcionar acceso fuera de la clase, expóngala a través de una propiedad pública:

public string SomeString { get { return someString; } }

De lo contrario, no lo use fuera de la clase. Usted no está destinado a

EDITAR

En base a su comentario de que en realidad está haciendo pruebas de control de calidad en el código de producción, cuestionaría la razón detrás de la necesidad de acceder a un valor privado durante sus pruebas. Realmente solo debería tener que probar las Propiedades / Métodos expuestos públicamente para verificar que todo funciona correctamente.

Dicho todo esto, si realmente no hay forma de evitar las cosas, puedes usar Reflection para obtener los valores.


Use reflexiones, pero prepárese para ser golpeado con un palo grande de un programador compañero.