首页 > 解决方案 > 如何在 C# 中执行跨层次调用

问题描述

我正在开发一个简单的 GUI 框架,但在调用受保护的虚拟方法时遇到了问题。

这是IKeyboardInputListenerService我用来接收键盘事件的服务接口和Control代表我所有 GUI 控件的基础的类。内部方法是被重构的方法。

public interface IKeyboardInputListenerService
{
    event EventHandler<KeyboardEventArgs> KeyPressed;
}

public abstract class Control
{
    public IKeyboardInputListenerService KeyboardInputListenerService { get; }

    protected Control(IKeyboardInputListenerService keyboardInputListenerService) =>
        KeyboardInputListenerService = keyboardInputListenerService;

    public event EventHandler<KeyboardEventArgs> KeyPressed;

    /* protected */ internal virtual void OnKeyPressed(object sender, KeyboardEventArgs args)
    {
        if (enabled && visible && focused && !args.Suppressed)
        {
            KeyPressed?.Invoke(sender, args);
            args.Suppressed = true;
        }
    }

    public void Activate() =>
        KeyboardInputListenerService.KeyPressed += new EventHandler<KeyboardEventArgs>(OnKeyPressed);
}

我还创建了一个ContainerControl应该包含子控件的类(如 Windows 窗体中的Panelor GroupBox)并覆盖虚拟方法:

public abstract class ContainerControl : Control
{
    private readonly ObservableCollection<Control> controls;

    protected ContainerControl(IKeyboardInputListenerService keyboardInputListenerService)
        : base(keyboardInputListenerService) =>
        controls = new ObservableCollection<Control>();

    /* protected */ internal override void OnKeyPressed(object sender, KeyboardEventArgs args)
    {
        foreach (Control control in controls)
            control.OnKeyPressed(sender, args);

        base.OnKeyPressed(sender, args);
    }
}

问题是,我无法决定将哪个修饰符用于诸如OnKeyPressed. 我想制作它们protected,但它会导致编译器错误:

错误 CS1540 无法通过“Control”类型的限定符访问受保护的成员“Control.OnKeyPressed(object, KeyboardEventArgs)”;限定符必须是“ContainerControl”类型(或派生自它)

我可以制作它们public,但我真的不认为这是一个好主意,因为除了解决跨层次调用引起的问题之外,没有任何理由这样做。我做了它们internal,但也有一个缺点:如果有人想创建用户控件,他们将无法接收事件,因此控件将无用。

问题是如何从派生类访问基类的虚拟方法,而不使这些方法可以公开访问。

标签: c#oopinheritancerefactoring

解决方案


利用protected internal

protected internal virtual void OnKeyPressed(object sender, KeyboardEventArgs args)
{ ... }

文档说:

protected internal类型或成员可以被声明它的程序集中的任何代码访问,也可以从另一个程序集中的派生类中访问。


推荐阅读