【问题标题】:Protected member not accessible in a derived class?在派生类中无法访问受保护的成员?
【发布时间】:2016-02-29 16:28:29
【问题描述】:

我有一个基类O,和两个派生类:A : OB : O,如下所示:

public abstract class O
{
    public O(string val)
    {
        this.Value = val;
    }

    private string value;
    public string Value
    {
        get { return this.value; }
        set
        {
            this.value = value;
            RaiseValueChanged();
        }
    }

    protected delegate void ValueChangedEventHandler();
    protected event ValueChangedEventHandler ValueChanged;
    protected void RaiseValueChanged()
    { if (ValueChanged != null) ValueChanged(); }
}

public sealed class A : O
{
    public A(string val)
        : base(val) { }
}

public sealed class B : O
{
    public B(string val, A instance)
        : base(val)
    {
        instanceA = instance;
    }

    private A instanceA;
    public A InstanceA
    {
        get { return instanceA; }
        set
        {
            instanceA = value;
        }
    }

    public void MyMethod()
    {
        //Some stuff..
    }
}

B.instanceA.ValueChanged 被提出时,我想调用B.MyMethod();,但当我发现我不能这样做时,我很惊讶:

public sealed class B : O
{
    public B(string val, A instance)
        : base(val)
    {
        instanceA = instance;
        //instanceA.ValueChanged += MyMethod;
    }

    private A instanceA;
    public A InstanceA
    {
        get { return instanceA; }
        set
        {
            //instanceA.ValueChanged -= MyMethod;
            instanceA = value;
            //instanceA.ValueChanged += MyMethod;
        }
    }

    public void MyMethod()
    {
        //Some stuff..
    }
}

根据MSDN

protected 关键字是成员访问修饰符。受保护的成员 可在其类内和派生类实例中访问。

但是虽然AB 都是O 的派生类,但它们不能使用彼此的基本保护成员。

在我的情况下,有什么建议可以解决这个问题吗? (而不是举办活动public

【问题讨论】:

  • 您为什么不想公开此活动?您是否只希望特定类型能够注册?
  • B 不继承自 A 这就是您无法访问此事件的原因。它们共享相同的基础但不继承。
  • @YuvalItzchakov 是的,我只想注册 O 派生类。

标签: c# oop event-handling protected access-modifiers


【解决方案1】:

公开并尝试一下。

这将保证两件事。

首先,关闭事件处理程序附加操作的调用者是从O派生的类的成员(或静态)方法,

其次,作为事件处理程序传递的委托是从 O 派生的类的成员(或静态)方法。

public delegate void ValueChangedEventHandler();

private event ValueChangedEventHandler valueChanged;
public event ValueChangedEventHandler ValueChanged
{
    add
    {
        if (!typeof(O).IsAssignableFrom(value.Method.DeclaringType))
        {
            throw new ArgumentException();
        }
        if (!typeof(O).IsAssignableFrom(new StackTrace().GetFrame(1).GetMethod().DeclaringType))
        {
            throw new ArgumentException();
        }
        valueChanged += value;
    }
    remove
    {
        valueChanged -= value;
    }
}

【讨论】:

    【解决方案2】:

    如果OAB 都在同一个程序集中,如果您不想公开,可以使用internal。否则,在这种情况下,您只能访问 public

    当您尝试以这种方式访问​​基类成员时,您只能通过public API 访问它,而不是通过protected。您可以通过尝试以下方法亲自查看:

    public sealed class B : O
    {
        public B(string val, O instance)
            : base(val)
        {
            instanceO = instance;
            instanceO.ValueChanged += MyMethod;
        }
    
        private O instanceO;
    }
    

    这仍然会产生编译错误。您可以在B 中访问ValueChanged,但只能通过B 的实例,正如引用中所说:

    protected 关键字是成员访问修饰符。受保护的成员可以在其类中访问,也可以通过派生类instances

    访问

    (强调我的)。

    【讨论】:

      【解决方案3】:

      您将 instanceA 作为类 B 的字段。 Protected 用于在派生类内部访问,而不是在外部访问。所以只有一种解决方案 - 使用 public。

      【讨论】:

      • 还有一个解决办法:internal
      • 但它也会使这个事件对程序集中的其他类可见
      • 是的,但正如我所见,Aly 想要隐藏事件,如此公开或内部 - 这并不重要
      【解决方案4】:

      但尽管AB 都是O 的派生类,但它们不能使用彼此的基本受保护成员。

      这是意料之中的。

      受保护的成员可以在其类中访问,也可以通过派生类实例访问。

      A 派生自 O,而不是 B,因此它无法看到 B 的受保护成员(反之亦然)。

      如果您希望这些课程能够看到彼此的成员/事件/等,那么您需要将它们设为公开。

      【讨论】: