如何在C#中获得私有字段的值?
我碰到一个问题,我需要访问一个类的私人领域。 例如:
class MyClass { private string someString; public MyClass( string someStringValue ) { someString = someStringValue; } }
我怎样才能得到MyClass之外的someString的价值?
更新:
对不起,我不能在这里使用属性,因为实际的生产代码是受保护的。 我是质量保证/开发人员,我需要一种方法来让这些私人编写用户验收testing。 所以我不能更改生产代码。 你能帮我吗?
正如其他人所说,由于该领域是私人的,你不应该试图用正常的代码来获得它。 唯一可以接受的是在unit testing期间,即使这样你也需要一个很好的理由来做到这一点(比如将一个私有variables设置为null,以便在exception块中的代码将被打中并且可以被testing)。
你可以使用类似下面的方法来获得该字段:
/// <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;
同样,这在大多数情况下不应该使用。
你不能 – 你不是这个意思。 这是私人的 。 如果这是别人的课,那么显然他们不希望你有机会进入这个领域。 事实上,它是私有的,可以让他们稍后改变实现 – 他们可能会把这个值作为另一个variables的一部分,或者重命名,或者如果为了实现公共API而不再需要它们,可能会完全消失。
如果是自己的课程,而且您确定希望其他人能够访问它,只需将其公开:
public string SomeString { get { return someString; } }
编辑:看到你的意见,你可以访问私人领域与反思…但一个验收testing,你不应该。 你应该testing公共API。 对于单元testing来说,有时候会弯曲这些规则是有意义的,并且把这个类视为一个“白盒子”而不是做“黑盒子”testing,但是对于验收testing,我肯定会坚持使用公共API。
如果这没有帮助,我build议你跟生产代码的开发者交谈:解释你为什么要访问,并要求他们通过一个属性公开它。 他们可以使它成为内部属性,并使用[InternalsVisibleTo]
在您的testing程序集中访问它。 我个人更喜欢使用reflection – 否则,如果生产代码以完全有效的方式变化,那么testing将会失败。
使用reflection,但准备用同伴程序员的大棒击中。
如果你是class级,你想在class级以外提供访问权限,可以通过公共资源公开:
public string SomeString { get { return someString; } }
否则,不要在课堂外使用它。 你不是为了
编辑
根据你的评论,你实际上正在对生产代码进行QAtesting,我会质疑在testing过程中需要访问私有价值的原因。 你真的应该只需要testing公开的属性/方法来validation所有东西都按预期运行。
所有这些说,如果真的没有办法解决的事情,你可以使用reflection来获取值。
你可以使用这个扩展方法。
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); } }
如果你正在使用它进行unit testing,我实现了@dcp的答案的通用版本,它提供了以下额外的function:
- 断言该字段是否存在
- 断言该值是否为“T”型。
- 将该值转换为types“T”。
码:
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; }
除了@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); }
把它作为一个公共财产
public string SomeString {get; private set;}
该属性声明将允许任何外部类读取variables,但不能修改它(因此私有的“setter”)。
编辑:刚才看到你的评论的其他答案。 你将不得不使用Relection来获得这样的私有variables。 正如在另一个build议的答案,一定要留意与程序员棍棒;)。 也就是说,谷歌沿着“用反思C#寻找财产价值”的思路。