简体   繁体   English

使用反射找到一个私有字段?

[英]Find a private field with Reflection?

Given this class鉴于这个类

class Foo
{
    // Want to find _bar with reflection
    [SomeAttribute]
    private string _bar;

    public string BigBar
    {
        get { return this._bar; }
    }
}

I want to find the private item _bar that I will mark with a attribute.我想找到我将用属性标记的私有项目 _bar。 Is that possible?那可能吗?

I have done this with properties where I have looked for an attribute, but never a private member field.我已经在我寻找属性的属性中完成了此操作,但从未寻找私有成员字段。

What are the binding flags that I need to set to get the private fields?我需要设置哪些绑定标志来获取私有字段?

Use BindingFlags.NonPublic and BindingFlags.Instance flags使用BindingFlags.NonPublicBindingFlags.Instance标志

FieldInfo[] fields = myType.GetFields(
                         BindingFlags.NonPublic | 
                         BindingFlags.Instance);

You can do it just like with a property:您可以像使用属性一样执行此操作:

FieldInfo fi = typeof(Foo).GetField("_bar", BindingFlags.NonPublic | BindingFlags.Instance);
if (fi.GetCustomAttributes(typeof(SomeAttribute)) != null)
    ...

Get private variable's value using Reflection:使用反射获取私有变量的值:

var _barVariable = typeof(Foo).GetField("_bar", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(objectForFooClass);

Set value for private variable using Reflection:使用反射设置私有变量的值:

typeof(Foo).GetField("_bar", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(objectForFoocClass, "newValue");

Where objectForFooClass is a non null instance for the class type Foo.其中 objectForFooClass 是类类型 Foo 的非空实例。

Nice Syntax With Extension Method带有扩展方法的好语法

You can access any private field of an arbitrary type with code like this:您可以使用如下代码访问任意类型的任何私有字段:

Foo foo = new Foo();
string c = foo.GetFieldValue<string>("_bar");

For that you need to define an extension method that will do the work for you:为此,您需要定义一个可以为您完成工作的扩展方法:

public static class ReflectionExtensions {
    public static T GetFieldValue<T>(this object obj, string name) {
        // Set the flags so that private and public fields from instances will be found
        var bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
        var field = obj.GetType().GetField(name, bindingFlags);
        return (T)field?.GetValue(obj);
    }
}

在考虑私有成员时需要注意的一件事是,如果您的应用程序以中等信任度运行(例如,当您在共享托管环境中运行时),它将找不到它们—— BindingFlags.NonPublic 选项将被忽略。

typeof(MyType).GetField("fieldName", BindingFlags.NonPublic | BindingFlags.Instance)

I use this method personally我个人使用这种方法

if (typeof(Foo).GetFields(BindingFlags.NonPublic | BindingFlags.Instance).Any(c => c.GetCustomAttributes(typeof(SomeAttribute), false).Any()))
{ 
    // do stuff
}

Here is some extension methods for simple get and set private fields and properties (properties with setter):下面是一些用于简单获取和设置私有字段和属性(带有 setter 的属性)的扩展方法:

usage example:用法示例:

 public class Foo { private int Bar = 5; } var targetObject = new Foo(); var barValue = targetObject.GetMemberValue("Bar");//Result is 5 targetObject.SetMemberValue("Bar", 10);//Sets Bar to 10

Code:代码:

    /// <summary>
    /// Extensions methos for using reflection to get / set member values
    /// </summary>
    public static class ReflectionExtensions
    {
        /// <summary>
        /// Gets the public or private member using reflection.
        /// </summary>
        /// <param name="obj">The source target.</param>
        /// <param name="memberName">Name of the field or property.</param>
        /// <returns>the value of member</returns>
        public static object GetMemberValue(this object obj, string memberName)
        {
            var memInf = GetMemberInfo(obj, memberName);

            if (memInf == null)
                throw new System.Exception("memberName");

            if (memInf is System.Reflection.PropertyInfo)
                return memInf.As<System.Reflection.PropertyInfo>().GetValue(obj, null);

            if (memInf is System.Reflection.FieldInfo)
                return memInf.As<System.Reflection.FieldInfo>().GetValue(obj);

            throw new System.Exception();
        }

        /// <summary>
        /// Gets the public or private member using reflection.
        /// </summary>
        /// <param name="obj">The target object.</param>
        /// <param name="memberName">Name of the field or property.</param>
        /// <returns>Old Value</returns>
        public static object SetMemberValue(this object obj, string memberName, object newValue)
        {
            var memInf = GetMemberInfo(obj, memberName);


            if (memInf == null)
                throw new System.Exception("memberName");

            var oldValue = obj.GetMemberValue(memberName);

            if (memInf is System.Reflection.PropertyInfo)
                memInf.As<System.Reflection.PropertyInfo>().SetValue(obj, newValue, null);
            else if (memInf is System.Reflection.FieldInfo)
                memInf.As<System.Reflection.FieldInfo>().SetValue(obj, newValue);
            else
                throw new System.Exception();

            return oldValue;
        }

        /// <summary>
        /// Gets the member info
        /// </summary>
        /// <param name="obj">source object</param>
        /// <param name="memberName">name of member</param>
        /// <returns>instanse of MemberInfo corresponsing to member</returns>
        private static System.Reflection.MemberInfo GetMemberInfo(object obj, string memberName)
        {
            var prps = new System.Collections.Generic.List<System.Reflection.PropertyInfo>();

            prps.Add(obj.GetType().GetProperty(memberName,
                                               System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance |
                                               System.Reflection.BindingFlags.FlattenHierarchy));
            prps = System.Linq.Enumerable.ToList(System.Linq.Enumerable.Where( prps,i => !ReferenceEquals(i, null)));
            if (prps.Count != 0)
                return prps[0];

            var flds = new System.Collections.Generic.List<System.Reflection.FieldInfo>();

            flds.Add(obj.GetType().GetField(memberName,
                                            System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance |
                                            System.Reflection.BindingFlags.FlattenHierarchy));

            //to add more types of properties

            flds = System.Linq.Enumerable.ToList(System.Linq.Enumerable.Where(flds, i => !ReferenceEquals(i, null)));

            if (flds.Count != 0)
                return flds[0];

            return null;
        }

        [System.Diagnostics.DebuggerHidden]
        private static T As<T>(this object obj)
        {
            return (T)obj;
        }
    }

Yes, however you will need to set your Binding flags to search for private fields (if your looking for the member outside of the class instance).是的,但是您需要设置绑定标志来搜索私有字段(如果您在类实例之外寻找成员)。

The binding flag you will need is: System.Reflection.BindingFlags.NonPublic您需要的绑定标志是:System.Reflection.BindingFlags.NonPublic

I came across this while searching for this on google so I realise I'm bumping an old post.我在谷歌上搜索这个时遇到了这个,所以我意识到我正在撞一个旧帖子。 However the GetCustomAttributes requires two params.但是 GetCustomAttributes 需要两个参数。

typeof(Foo).GetFields(BindingFlags.NonPublic | BindingFlags.Instance)
.Where(x => x.GetCustomAttributes(typeof(SomeAttribute), false).Length > 0);

The second parameter specifies whether or not you wish to search the inheritance hierarchy第二个参数指定是否要搜索继承层次结构

If your .Net framework is greater than 4.5.如果您的 .Net 框架大于 4.5。 You can use GetRuntimeFields method.您可以使用 GetRuntimeFields 方法。

This method returns all fields that are defined on the specified type, including inherited, non-public, instance, and static fields.此方法返回在指定类型上定义的所有字段,包括继承、非公共、实例和静态字段。

https://docs.microsoft.com/en-us/dotnet/api/system.reflection.runtimereflectionextensions.getruntimefields?view=net-6.0 https://docs.microsoft.com/en-us/dotnet/api/system.reflection.runtimereflectionextensions.getruntimefields?view=net-6.0

var foo = new Foo();
var fooFields = foo.GetType().GetRuntimeFields()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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