使用反射访问基类和子类中的私有字段

时间:2012-11-08 13:54:44

标签: c# reflection

我有一个简单的程序:

using System;
using System.Reflection;

namespace PlayWithReflection
{
class MyDisposable:IDisposable
{
    private  string _name;

    public MyDisposable(string name)
    {
        this._name = name;
    }

    public string Name
    {
        get { return _name; }
    }

    public void Dispose()
    {
        Console.WriteLine(_name + " is disposed");
    }
}

class MyBaseClass : IDisposable
{
    protected MyDisposable _baseProtectedDisposableA = new MyDisposable("_baseProtectedDisposableA");
    private MyDisposable _baseDisposableB = new MyDisposable("_baseDisposableB");

    public MyDisposable BaseProtectedDisposableA
    {
        get { return _baseProtectedDisposableA; }
    }

    public MyDisposable BaseDisposableB
    {
        get { return _baseDisposableB; }
    }

    public void Dispose()
    {
        var fieldInfos = this.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);

        foreach (var fieldInfo in fieldInfos)
        {
            var value = fieldInfo.GetValue(this);
            if (value is IDisposable)
            {
                ((IDisposable)value).Dispose();
                fieldInfo.SetValue(this, null);
            }
        }
    }
}


class MyClass : MyBaseClass
{
    private MyDisposable _disposableC = new MyDisposable("_disposableC");
    private MyDisposable _disposableD = new MyDisposable("_disposableD");

    public MyDisposable DisposableC
    {
        get { return _disposableC; }
    }

    public MyDisposable DisposableD
    {
        get { return _disposableD; }
    }
}



class Program
{
    static void Main(string[] args)
    {
        using(MyBaseClass instance = new MyClass())
        {
           Console.WriteLine(instance.BaseProtectedDisposableA.Name + " is telling his name...");
           Console.WriteLine("--------------------------------------------------------");
        }

        Console.ReadKey();
    }
}
}

它打印的内容如下:

_baseProtectedDisposableA is telling his name...
-------------------------------------------------------
_disposableC is disposed
_disposableD is disposed
_baseProtectedDisposableA is disposed

问题是如何打印这个:

_baseProtectedDisposableA is telling his name...
-------------------------------------------------------
_disposableC is disposed
_disposableD is disposed
_baseProtectedDisposableA is disposed
_baseDisposableB is disposed

或者,换句话说,我的私有字段_baseDisposableB在哪里,以及如何处理它?<​​/ p>

谢谢。

2 个答案:

答案 0 :(得分:1)

  

我的私人字段_baseDisposableB

在哪里

阅读BindingFlags枚举上的文档:

  

FlattenHierarchy 指定应返回层次结构中的公共和受保护静态成员。不返回继承类中的私有静态成员。静态成员包括字段,方法,事件和属性。不返回嵌套类型。

因此不返回基类的私有成员。这是有道理的,因为私有成员不能假设可以从派生类访问。

  

如何处理它?<​​/ p>

由于访问私有成员无论如何都是一个黑客攻击,我不会尝试从派生类中处理它。我会直接在基类中明确Dispose

public void Dispose()
{
    var fieldInfos = this.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);

    foreach (var fieldInfo in fieldInfos)
    {
        var value = fieldInfo.GetValue(this);
        if (value is IDisposable)
        {
            ((IDisposable)value).Dispose();
            fieldInfo.SetValue(this, null);
        }
    }
    _baseDisposableB.Dispose();
}

虽然我认为你有理由想要使用反射而不是明确地处理成员......

答案 1 :(得分:0)

使用GetType().GetFields(...)无法获取基本类型的私有字段。您必须从基本类型本身获取字段。

示例:使用以下两种方法替换Dispose方法:

public void Dispose()
{
    var type = GetType();
    while (type != null)
    {
        DisposeFields(type);
        type = type.BaseType;
    }
}

private void DisposeFields(Type type)
{
    var fieldInfos = type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic);

    foreach (var fieldInfo in fieldInfos)
    {
        var value = fieldInfo.GetValue(this) as IDisposable;
        if (value == null) continue;

        value.Dispose();
        fieldInfo.SetValue(this, null);
    }
}

这将通过继承层次结构和Dispose基本类型的字段(如果它们是一次性的)。

结果:

_baseProtectedDisposableA is telling his name...
--------------------------------------------------------
_disposableC is disposed
_disposableD is disposed
_baseProtectedDisposableA is disposed
_baseDisposableB is disposed