关于c#:从基类反映私有字段

Reflecting a private field from a base class

结构如下:

MyClass:超类2

超类2:超类1

superclass2在product.web中,superclass1在.net system.web程序集中

我试图将一个值强制到超类1上的私有布尔字段中。但无论我怎么尝试,我都无法让这些场从反射中回来。

我正在使用以下代码和不同的bindingflag组合,但到目前为止还没有任何效果。超类1是一个抽象类。

1
((SuperClass1)this).GetType().GetFields(System.Reflection.BindingFlags.NonPublic);

笔记:当我使用get properties()时,我会得到一个很好的大列表,但是当我指定任何bindingFlags时,即使有匹配的属性,我也什么也得不到。这笔交易是什么?

此外,该字段未标记为"内部"

显然,我将使用getfield(字符串名称,bindingFlags),但我甚至无法让getFlags()工作。

更新:我已尝试按建议添加bindingFlags.Instance,但它不起作用(仍如预期的那样)。我得到了2个字段,它们来自类superclass1继承自。与GetField一起使用时返回空值(字符串名称、标志)

这是我要为其获取字段的基类的代码

1
2
3
4
5
public abstract class BaseValidator : Label, IValidator
  {
    private bool propertiesChecked;
...
}


您可以在继承链中手动向上移动以获取基字段:

考虑到这些类别:

1
2
3
4
5
6
7
8
9
10
11
12
13
class SuperClass1
{
    private int myField;
}

class SuperClass2 : SuperClass1
{
}

class MyClass : SuperClass2
{

}

这应该有效:

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

这里面有一个更通用的解决方案,所以回答:不要从getType()中获取字段。getFields with bindingFlag.default


类似于经纪人的解决方案,你可以这样做,让它更通用一点:

1
2
3
class Base { private int _baseField; }
class Derived : Base { }
class Mine : Derived { }

然后:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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.");
}

作为一种实用方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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);
}

然后:

1
2
3
Mine m = new Mine();

SetField(m,"_baseField", 10);


扩展方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/// <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) is Type)
        ;
    return fi;
}

我认为您需要添加System.Reflection.BindingFlags.Instance标志。使用将其与非公共标志组合。

编辑:

好像是经纪人做的对。我写了下面的快速测试。

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

它正确地报告了您要查找的字段。(测试从basevalidator派生)


如果层次结构是静态的,那么最简单的方法是:

1
var field = typeof(SuperClass1).GetField("_privateBaseField",System.Reflection.BindingFlags.NonPublic);