简体   繁体   English

如何使用反射获取私有字段的值?

[英]How to get the value of private field using reflection?

I ran into a problem that I need to access to private field of a class.我遇到了一个问题,我需要访问类的私有字段。 For example:例如:

class MyClass 
{
    private string someString;

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

How can I get the value of someString outside MyClass ?如何在 MyClass 之外获取 someString 的值?

Update:更新:

Sorry, I cannot use property here since the the actual production code is protected.抱歉,我不能在这里使用属性,因为实际的生产代码是受保护的。 I'm a QA/Dev, I need a way to get those private for writing User Acceptance Test.我是一名 QA/Dev,我需要一种方法来将这些私有化以编写用户验收测试。 So I cannot change production code.所以我不能更改生产代码。 Can you help?你能帮我吗?

As others have said, since the field is private you should not be trying to get it with normal code.正如其他人所说,由于该字段是私有的,因此您不应该尝试使用普通代码来获取它。 The only time this is acceptable is during unit testing, and even then you need a good reason to do it (such as setting a private variable to null so that code in an exception block will be hit and can be tested).唯一可以接受的情况是在单元测试期间,即便如此,您也需要一个很好的理由来这样做(例如将私有变量设置为 null,以便异常块中的代码将被命中并可以进行测试)。

You could use something like the method below to get the field:您可以使用类似下面的方法来获取字段:

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

So you could call this like:所以你可以这样称呼它:

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

Again, this should not be used in most cases.同样,这不应在大多数情况下使用。

You can't - and you're not meant to.你不能——你也不是故意的。 It's private .这是私人的 If this is someone else's class, then clearly they don't want you to have access to that field.如果这是其他人的课程,那么显然他们不希望您访问该领域。 The fact that it's private allows them to change the implementation later - they might end up with that value as part of another variable, or renamed, or possibly gone completely if it's no longer required in order to implement the public API.它是私有的这一事实允许他们稍后更改实现 - 他们可能最终将该值作为另一个变量的一部分,或者重命名,或者如果不再需要它来实现公共 API,则可能完全消失。

If it's your own class and you're sure you want other people to be able to access it, just expose it with a property:如果它是您自己的类并且您确定希望其他人能够访问它,只需使用属性公开它:

public string SomeString { get { return someString; } }

EDIT: Having seen your comments, you can access the private fields with reflection... but for an acceptance test you shouldn't have to.编辑:看到您的评论后,您可以通过反射访问私有字段……但是对于验收测试,您不必这样做。 You should be testing the public API.您应该测试公共 API。 For unit tests it makes sense to bend the rules sometimes, and treat the class as a "white box" rather than doing "black box" testing, but for acceptance tests I would definitely stick to the public API.对于单元测试,有时弯曲规则是有意义的,并将类视为“白盒”而不是“黑盒”测试,但对于验收测试,我肯定会坚持使用公共 API。

If this doesn't help, I suggest you talk to the developers of the production code: explain why you want access, and ask them to expose it via a property.如果这没有帮助,我建议您与生产代码的开发人员交谈:解释您为什么要访问,并要求他们通过属性公开它。 They could make it an internal property, and use [InternalsVisibleTo] to get access to it in your test assembly.他们可以将其设为内部属性,并使用[InternalsVisibleTo]在您的测试程序集中访问它。 I would personally prefer this over using reflection - otherwise if the production code changes in a perfectly valid way, your tests will fail when they shouldn't.我个人更喜欢使用反射 - 否则,如果生产代码以完全有效的方式更改,您的测试将在不应该失败时失败。

I ran into a problem that I need to access to private field of a class.我遇到一个问题,我需要访问班级的私有领域。 For example:例如:

class MyClass 
{
    private string someString;

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

How can I get the value of someString outside MyClass ?我如何在MyClass之外获取someString的值?

Update:更新:

Sorry, I cannot use property here since the the actual production code is protected.抱歉,由于实际的生产代码受到保护,因此我无法在此处使用属性。 I'm a QA/Dev, I need a way to get those private for writing User Acceptance Test.我是QA / Dev,我需要一种方法来使这些人私有以编写用户验收测试。 So I cannot change production code.因此,我无法更改生产代码。 Can you help?你能帮我吗?

Here is a working generics version as clean as I can get it.这是一个工作的泛型版本,我可以得到它。

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

usage用法

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

If it's your class and you want to provide access to it outside of the class, expose it via a public property:如果它是您的类并且您想在类之外提供对它的访问,请通过公共属性公开它:

public string SomeString { get { return someString; } }

Otherwise, don't use it outside of the class.否则,不要在课堂之外使用它。 You're not meant to.你不是故意的。

EDIT编辑

Based on your comment that you're actually doing QA testing on production code, I'd question the reasoning behind needing to access a private value during your testing.根据您的评论,您实际上是在对生产代码进行 QA 测试,我会质疑在测试期间需要访问私有值的原因。 You really should only have to test the publicly exposed Properties/Methods to verify that everything is functioning as intended.你真的应该只需要测试公开暴露的属性/方法来验证一切是否按预期运行。

All that being said, if there's really no way around things you can use Reflection to get the values.话虽如此,如果真的没有办法解决问题,您可以使用反射来获取值。

If you are using it for unit testing, I implemented a generic version of @dcp 's answer which provides the following extras:如果您将它用于单元测试,我实现了 @dcp 答案的通用版本,它提供了以下附加功能:

  • Asserts if the field exists断言该字段是否存在
  • Asserts if the value is of type "T".断言值是否为“T”类型。
  • Converts the value to the type "T".将值转换为“T”类型。

Code:代码:

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

You can use this Extension method.您可以使用此扩展方法。

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

in addition to @dcp answer, this can be a lot easier by turning it into Generic Function...除了@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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM