C# 从基类反映私有字段

C# 从基类反映私有字段,c#,.net,reflection,C#,.net,Reflection,结构如下: MyClass:超类2 超类2:超类1 超类2位于Product.Web中,而超类1位于.NET System.Web程序集中 我试图在超类1上的私有布尔字段中强制输入一个值。但无论我尝试什么,我都无法从反射中恢复场 我将下面的代码与不同的BindingFlag组合一起使用,但到目前为止没有任何效果。超类1是一个抽象类 ((SuperClass1)this).GetType().GetFields(System.Reflection.BindingFlags.NonPublic);

结构如下:

MyClass:超类2

超类2:超类1

超类2位于Product.Web中,而超类1位于.NET System.Web程序集中

我试图在超类1上的私有布尔字段中强制输入一个值。但无论我尝试什么,我都无法从反射中恢复场

我将下面的代码与不同的BindingFlag组合一起使用,但到目前为止没有任何效果。超类1是一个抽象类

((SuperClass1)this).GetType().GetFields(System.Reflection.BindingFlags.NonPublic);
注意事项: 当我使用GetProperties()时,我会得到一个很好的大列表,但是当我指定任何bindingflags时,即使有匹配的属性,我也不会得到任何结果。怎么回事

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

很明显,我会使用GetField(字符串名、BindingFlags),但我甚至无法让GetFlags()工作

更新:我已尝试添加BindingFlags.Instance(如建议的那样),但不起作用(如预期的那样)。我从超类1继承的类中返回了两个字段。与GetField(字符串名称、标志)一起使用时返回null

下面是我试图获取字段的基类的代码

public abstract class BaseValidator : Label, IValidator
  {
    private bool propertiesChecked;
...
}

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

编辑:

看来碎玻璃是对的。我编写了以下快速测试

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

它正确地报告了您要查找的字段。(测试源自BaseValidator)

您可以手动进入继承链以获取基本字段:

鉴于这些类别:

class SuperClass1
{
    private int myField;
}

class SuperClass2 : SuperClass1
{
}

class MyClass : SuperClass2
{

}
这应该起作用:

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

这个答案中有一个更通用的解决方案:

与BrokenGlass的解决方案类似,您可以这样做使它更通用:

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

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.");
}
Mine m = new Mine();

SetField(m, "_baseField", 10);
作为一种实用方法:

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);
}
然后:

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.");
}
Mine m = new Mine();

SetField(m, "_baseField", 10);

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

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

扩展方法:

/// <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;
}
//
///从类型“t”本身或其最派生的类型返回与“name”匹配的FieldInfo
///基类型(与“System.type.GetField”不同)。如果未找到匹配项,则返回null。
/// 
公共静态字段信息GetPrivateField(此类型为t,字符串名称)
{
const BindingFlags bf=BindingFlags.Instance|
BindingFlags.NonPublic|
BindingFlags.DeclaredOnly;
FieldInfo-fi;
while((fi=t.GetField(name,bf))==null&&(t=t.BaseType)!=null)
;
返回fi;
}

很抱歉问了一个愚蠢的问题,但你为什么要这样做?:)好问题。由于Product.Web.SuperClass2的原因,我不得不将此作为一种变通方法来实现对他们应该已经支持但不支持的功能的支持。基本上,API有一个虚拟方法,但总是调用基本实现。所以我需要更改字段的值,这样它就不会进行某些检查,这样我就可以运行我的代码。请不要问“为什么要这样做?”——这既没有帮助也没有建设性——这样做有一百万个有效的理由,而且都是不同的。显然,代码有味道,但教条不会帮助我们90万人,他们将通过谷歌被扔到这里。为了反映私有领域,你需要有一个许可。您能在System.Web中提供您试图访问的字段和从中派生的类吗?(不过,您肯定需要实例标志才能正常工作。)“System.Web.UI.WebControls.BaseValidator”,我想设置属性检查是什么做的。我在里面没看到BaseType。现在让我们希望这次冒险能解决我最初的问题。。。