【问题标题】:Find a private field with Reflection?使用反射找到一个私有字段?
【发布时间】:2010-09-10 21:19:09
【问题描述】:

给定这个类

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

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

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

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

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

【问题讨论】:

    标签: c# .net reflection .net-attributes


    【解决方案1】:

    使用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(),您将自动获得实例成员。但是,当您显式设置绑定标志时,它会删除实例成员的默认包含。这没有道理。标志枚举应该是附加的。
    【解决方案2】:

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

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

    【讨论】:

    • 很抱歉发布了极端的死灵帖子,但这让我失望了。如果没有找到属性,GetCustomAttributes(Type) 不会返回 null,它只是返回一个空数组。
    【解决方案3】:

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

    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 的非 null 实例。

    【讨论】:

    【解决方案4】:

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

    【讨论】:

    • jammycakes 你能举个共享主机环境的例子吗?我在想 iis 与多个应用程序是你得到的?
    • 我说的是 IIS 在 machine.config 级别锁定为部分信任的位置。现在,您通常只能在便宜且讨厌的共享网络托管计划中找到此功能(我不再使用此类计划)-如果您可以完全控制您的服务器,那么它就不会真正相关,因为完全信任是默认。
    【解决方案5】:

    带有扩展方法的好语法

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

    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 来说是完美的!太棒了!
    【解决方案6】:
    typeof(MyType).GetField("fieldName", BindingFlags.NonPublic | BindingFlags.Instance)
    

    【讨论】:

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

    我个人使用这个方法

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

    【讨论】:

      【解决方案8】:

      这里有一些简单的获取和设置私有字段和属性的扩展方法(带有setter的属性):

      用法示例:

          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
      

      代码:

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

      【讨论】:

        【解决方案9】:

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

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

        【讨论】:

          【解决方案10】:

          我在 google 上搜索时遇到了这个问题,所以我意识到我碰到了一个旧帖子。但是 GetCustomAttributes 需要两个参数。

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

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

          【讨论】:

            猜你喜欢
            • 2019-01-23
            • 1970-01-01
            • 2021-12-07
            • 1970-01-01
            • 2014-04-13
            • 2013-02-25
            • 2014-10-13
            • 2012-01-23
            • 1970-01-01
            相关资源
            最近更新 更多