ChatGPT解决这个技术问题 Extra ChatGPT

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

鉴于这个类

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

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

我想找到我将用属性标记的私有项目 _bar。那可能吗?

我已经在我寻找属性的属性中完成了此操作,但从未寻找私有成员字段。

我需要设置哪些绑定标志来获取私有字段?


B
Bob King

使用 BindingFlags.NonPublicBindingFlags.Instance 标志

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

我只能通过提供“BindingFlags.Instance”绑定标志来使其工作。
我已经确定了你的答案。否则太混乱了。 Abe Heidebrecht 的回答是最完整的。
效果很好 - 仅供参考 VB.NET 版本 Me.GetType().GetFields(Reflection.BindingFlags.NonPublic 或 Reflection.BindingFlags.Instance)
仅当您想获取实例方法时才使用实例绑定标志。如果您想获得一个私有静态方法,您可以使用 (BindingFlags.NonPublic | BindingFlags.Static)
每次我对非公共成员使用反射时,BindingFlags.Instance 都会让我感到不安。如果您使用带 Default=0 BindingFlags 的 GetFields(),您将自动获得实例成员。但是,当您显式设置绑定标志时,它会删除实例成员的默认包含。这没有道理。标志枚举应该是附加的。
A
Abe Heidebrecht

您可以像使用属性一样执行此操作:

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

很抱歉发布了极端的死灵贴,但这让我很失望。如果未找到该属性,GetCustomAttributes(Type) 将不会返回 null,它只是返回一个空数组。
D
David Basarab

使用反射获取私有变量的值:

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

使用反射设置私有变量的值:

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

其中 objectForFooClass 是类类型 Foo 的非空实例。


类似的答案描述了易于使用的功能 GetInstanceField(typeof(YourClass), instance, "someString") as string How to get the value of private field in C#?
C
Community

带有扩展方法的好语法

您可以使用如下代码访问任意类型的任何私有字段:

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

为此,您需要定义一个可以为您完成工作的扩展方法:

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

伙计,这对于在我的代码中访问受保护的变量而不将其暴露给 NLua 来说是完美的!惊人的!
j
jammycakes

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


jammycakes 你能举一个共享托管环境的例子吗?我在想带有多个应用程序的 iis 是你得到的吗?
我说的是 IIS 在 machine.config 级别锁定为部分信任的位置。现在,您通常只能在便宜且讨厌的共享网络托管计划中找到它(我不再使用的类似计划)-如果您可以完全控制您的服务器,那么它就不会真正相关,因为完全信任是默认。
D
Darren Kopp
typeof(MyType).GetField("fieldName", BindingFlags.NonPublic | BindingFlags.Instance)

我不知道该领域的名称。我想在没有名称和属性的情况下找到它。
要查找字段名称,在 Visual Studio 中很容易做到。在变量处设置断点,查看其字段(包括私有的,通常以m_fieldname开头)。将该 m_fieldname 替换为上面的命令。
s
sa_ddam213

我个人使用这种方法

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

e
epsi1on

下面是一些用于简单获取和设置私有字段和属性(带有 setter 的属性)的扩展方法:

用法示例:

公共类 Foo { 私有 int Bar = 5; } var targetObject = new Foo(); var barValue = targetObject.GetMemberValue("Bar");//结果为5 targetObject.SetMemberValue("Bar", 10);//设置Bar为10

代码:

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

m
mmattax

是的,但是您需要设置绑定标志来搜索私有字段(如果您在类实例之外寻找成员)。

您需要的绑定标志是:System.Reflection.BindingFlags.NonPublic


G
Gunner

我在谷歌上搜索这个时遇到了这个,所以我意识到我正在撞一个旧帖子。但是 GetCustomAttributes 需要两个参数。

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

第二个参数指定是否要搜索继承层次结构


A
Ashwin Rajaram

如果您的 .Net 框架大于 4.5。您可以使用 GetRuntimeFields 方法。

此方法返回在指定类型上定义的所有字段,包括继承、非公共、实例和静态字段。

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()