Reflecting a private field from a base class

前端 未结 5 1177
爱一瞬间的悲伤
爱一瞬间的悲伤 2020-11-29 07:34

Here is the structure:

MyClass : SuperClass2

SuperClass2 : SuperClass1

superClass2 is in Product.Web and SuperClass1 is in the .NET System.Web assemb

相关标签:
5条回答
  • 2020-11-29 07:53

    I think you need to add the System.Reflection.BindingFlags.Instance flag. Use | to combine it with the NonPublic flag.

    EDIT:

    Looks like BrokenGlass has it right. I wrote the following quick test.

    var fields = test.GetType().BaseType.GetFields(BindingFlags.Instance | BindingFlags.NonPublic);
    foreach (var field in fields)
    {
         System.Console.WriteLine(field.Name);
    }
    

    It correctly reports the field you were looking for. (Test is derived from BaseValidator)

    0 讨论(0)
  • 2020-11-29 07:57

    You can manually go up in the inheritance chain to get the base fields:

    Given these classes:

    class SuperClass1
    {
        private int myField;
    }
    
    class SuperClass2 : SuperClass1
    {
    }
    
    class MyClass : SuperClass2
    {
    
    }
    

    This should work:

    var myObj = new MyClass();
    var myField = typeof(MyClass).BaseType
                                 .BaseType
                                 .GetField("myField", BindingFlags.Instance | BindingFlags.NonPublic);
    

    There's a more generic solution in this SO answer: Not getting fields from GetType().GetFields with BindingFlag.Default

    0 讨论(0)
  • 2020-11-29 08:06

    If hierarchy is static, the simplest way to do this:

    var field = typeof(SuperClass1).GetField("_privateBaseField",System.Reflection.BindingFlags.NonPublic);
    
    0 讨论(0)
  • 2020-11-29 08:10

    Extension method:

    /// <summary>
    /// Returns the FieldInfo matching 'name' from either type 't' itself or its most-derived 
    /// base type (unlike 'System.Type.GetField'). Returns null if no match is found.
    /// </summary>
    public static FieldInfo GetPrivateField(this Type t, String name)
    {
        const BindingFlags bf = BindingFlags.Instance | 
                                BindingFlags.NonPublic | 
                                BindingFlags.DeclaredOnly;
    
        FieldInfo fi;
        while ((fi = t.GetField(name, bf)) == null && (t = t.BaseType) != null)
            ;
        return fi;
    }
    
    0 讨论(0)
  • 2020-11-29 08:11

    In a similar vein to BrokenGlass's solution, you could do this to make it a bit more generic:

    class Base { private int _baseField; }
    class Derived : Base { }
    class Mine : Derived { }
    

    And then:

    Type t = typeof(Mine);
    FieldInfo fi = null;
    
    while (t != null) 
    {
        fi = t.GetField("_baseField", BindingFlags.Instance | BindingFlags.NonPublic);
    
        if (fi != null) break;
    
        t = t.BaseType; 
    }
    
    if (fi == null)
    {
        throw new Exception("Field '_baseField' not found in type hierarchy.");
    }
    

    As a utility method:

    public static void SetField(object target, string fieldName, object value)
    {
        if (target == null)
        {
            throw new ArgumentNullException("target", "The assignment target cannot be null.");
        }
    
        if (string.IsNullOrEmpty(fieldName))
        {
            throw new ArgumentException("fieldName", "The field name cannot be null or empty.");
        }
    
        Type t = target.GetType();
        FieldInfo fi = null;
    
        while (t != null)
        {
            fi = t.GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic);
    
            if (fi != null) break;
    
            t = t.BaseType; 
        }
    
        if (fi == null)
        {
            throw new Exception(string.Format("Field '{0}' not found in type hierarchy.", fieldName));
        }
    
        fi.SetValue(target, value);
    }
    

    And then:

    Mine m = new Mine();
    
    SetField(m, "_baseField", 10);
    
    0 讨论(0)
提交回复
热议问题