【问题标题】:Accessing a class protected field without modifying original class在不修改原始类的情况下访问类保护字段
【发布时间】:2012-03-14 08:26:51
【问题描述】:

我正在使用一些公开某种类型(由方法返回)的第 3 方库。

这种类型有一些我感兴趣的受保护字段,但是我无法使用它们,因为它们的可见性是受保护的

这里是问题的简化:

public class A
    {
        protected object Something;

        public A Load()
        {
            return new A();
        }
    }

    public class ExtendedA : A
    {
        public void DoSomething()
        {
            // Get an instance.
            var a = Load();

            // Access protected fields (doesn't compile).
            a.Something = ....
        }
    }

有什么简单的方法可以实现吗?

【问题讨论】:

  • 编译器的错误信息是什么?
  • 我不明白,该字段是受保护的,但是当您从该类派生时,您仍然无法访问该成员?
  • 在实例上调用.Something **已知为ExtendedAA 之间存在很大差异;这就是受保护者不允许您访问的原因。 Eric Lippert 有一系列关于“为什么我不能从派生类访问受保护的成员?”的文章。 - 寻找他们?

标签: c# .net oop


【解决方案1】:

说明

您可以使用this.Something 访问字段,因为您的类派生自class A

如果要创建class A 的实例,而不是派生类,则只能使用反射访问该字段。

使用反射的示例

public class ExtendedA : A
{
    public void DoSomething()
    {
        // Get an instance.
        var a = Load();

        //get the type of the class
        Type type = a.GetType();
        BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic;

        // get the field info
        FieldInfo finfo = type.GetField("Something", bindingFlags);

        // set the value 
        finfo.SetValue(a, "Hello World!");

        // get the value
        object someThingField = finfo.GetValue(a);
    }
}

更多信息

【讨论】:

  • 问题是我需要访问特定实例上的字段,而不是“this”
【解决方案2】:

那是因为您实际上无法访问它。 除了this(或base)之外,您不能在任何实例上调用受保护的方法。 仅仅因为你的代码恰好在 A 的后代中并不意味着这条规则会突然改变。

Eric Lippert 在他的博客中有一个很好的解释: http://blogs.msdn.com/b/ericlippert/archive/2005/11/09/why-can-t-i-access-a-protected-member-from-a-derived-class.aspx

【讨论】:

  • 您可以对除thisbase 以外的值调用受保护的方法,前提是它们的类型已知与出现代码的类的类型相同或派生自该类的类型。例如,如果你的基类 B 带有受保护的方法 M(),那么派生类 D 可以调用 (new D()).M()。
  • @EricLippert:我再次发现自己重新阅读了我指向的博客条目,以了解真正发生的事情。谢谢:)
  • 不客气。另请注意,这篇原始文章产生了六篇探索该规则各个方面的文章。请参阅blogs.msdn.com/b/ericlippert/archive/tags/protected 了解其中的很多内容。
  • 干杯!我已经阅读您的博客文章有一段时间了,并且非常喜欢它们。我是一个狂热的读者,但显然和可悲的是,我还不够透彻:)
【解决方案3】:

通过从 A 继承,您可以创建一个新类 (ExtendedA),它有一个成员 Something,您可以从 ExtendedA 中访问该成员

public class ExtendedA : A 
{ 
    public void DoSomething() 
    { 

        // works fine
        this.Something = .... 
    } 
} 

继承不能让您访问 A 的实例来改变某事

public class ExtendedA : A 
{ 
    public void DoSomething() 
    { 
        var a = new A();

        // access level error
        a.Something = .... 
    } 
} 

如果您想使用 Something 值,您可以在 ExtendedA 中这样做,但只能在 ExtendedA 实例自己的 Something 副本上使用。

hth,
艾伦。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-13
    • 2011-10-31
    • 1970-01-01
    • 2013-05-27
    相关资源
    最近更新 更多