[英]How to get the value of private field using reflection?
我遇到了一个问题,我需要访问类的私有字段。 例如:
class MyClass
{
private string someString;
public MyClass( string someStringValue )
{
someString = someStringValue;
}
}
如何在 MyClass 之外获取 someString 的值?
抱歉,我不能在这里使用属性,因为实际的生产代码是受保护的。 我是一名 QA/Dev,我需要一种方法来将这些私有化以编写用户验收测试。 所以我不能更改生产代码。 你能帮我吗?
正如其他人所说,由于该字段是私有的,因此您不应该尝试使用普通代码来获取它。 唯一可以接受的情况是在单元测试期间,即便如此,您也需要一个很好的理由来这样做(例如将私有变量设置为 null,以便异常块中的代码将被命中并可以进行测试)。
您可以使用类似下面的方法来获取字段:
/// <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);
}
所以你可以这样称呼它:
string str = GetInstanceField(typeof(YourClass), instance, "someString") as string;
同样,这不应在大多数情况下使用。
你不能——你也不是故意的。 这是私人的。 如果这是其他人的课程,那么显然他们不希望您访问该领域。 它是私有的这一事实允许他们稍后更改实现 - 他们可能最终将该值作为另一个变量的一部分,或者重命名,或者如果不再需要它来实现公共 API,则可能完全消失。
如果它是您自己的类并且您确定希望其他人能够访问它,只需使用属性公开它:
public string SomeString { get { return someString; } }
编辑:看到您的评论后,您可以通过反射访问私有字段……但是对于验收测试,您不必这样做。 您应该测试公共 API。 对于单元测试,有时弯曲规则是有意义的,并将类视为“白盒”而不是“黑盒”测试,但对于验收测试,我肯定会坚持使用公共 API。
如果这没有帮助,我建议您与生产代码的开发人员交谈:解释您为什么要访问,并要求他们通过属性公开它。 他们可以将其设为内部属性,并使用[InternalsVisibleTo]
在您的测试程序集中访问它。 我个人更喜欢使用反射 - 否则,如果生产代码以完全有效的方式更改,您的测试将在不应该失败时失败。
我遇到一个问题,我需要访问班级的私有领域。 例如:
class MyClass
{
private string someString;
public MyClass( string someStringValue )
{
someString = someStringValue;
}
}
我如何在MyClass之外获取someString的值?
抱歉,由于实际的生产代码受到保护,因此我无法在此处使用属性。 我是QA / Dev,我需要一种方法来使这些人私有以编写用户验收测试。 因此,我无法更改生产代码。 你能帮我吗?
这是一个工作的泛型版本,我可以得到它。
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);
}
用法
var str = (string)GetInstanceField(instance, "someString");
如果它是您的类并且您想在类之外提供对它的访问,请通过公共属性公开它:
public string SomeString { get { return someString; } }
否则,不要在课堂之外使用它。 你不是故意的。
编辑
根据您的评论,您实际上是在对生产代码进行 QA 测试,我会质疑在测试期间需要访问私有值的原因。 你真的应该只需要测试公开暴露的属性/方法来验证一切是否按预期运行。
话虽如此,如果真的没有办法解决问题,您可以使用反射来获取值。
如果您将它用于单元测试,我实现了 @dcp 答案的通用版本,它提供了以下附加功能:
代码:
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;
}
您可以使用此扩展方法。
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);
}
}
除了@dcp 答案之外,将其转换为通用函数会更容易...
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);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.