【问题标题】:Can C# methods in child classes have different argument type (that derives from an argument type for a method in parent class)?子类中的 C# 方法能否具有不同的参数类型(从父类中方法的参数类型派生)?
【发布时间】:2021-08-18 09:59:05
【问题描述】:

对于一个措辞不当的问题,我们深表歉意。 我正在制作一些代表简单游戏的 GUI 的类。 GUI 由不同的元素组成,由派生自某个共同祖先 UIElement 的类表示。

class UIElement
{
    public virtual void Update(UpdateArgs args) { }

    public class UpdateArgs { }
}

每个元素都应该包含一个 Update() 方法,但是对于不同的元素,需要不同的参数(即,对于进度条,应该有一些代表完整度的数字,对于按钮,应该有一些布尔值来确定它是否可点击,等等) . 所以基本上我希望能够覆盖 Update() 方法,将其参数类型更改为从原始方法的参数类型派生的类型,如下所示:

class ProgressBar : UIElement
{
    public override void Update(UpdateArgs args)
    {
        base.Update(args);
        //Set fullness
    }

    public class UpdateArgs : UIElement.UpdateArgs
    {
        double fullness;
    }
}

上面的代码不起作用,因为编译器找不到合适的方法来覆盖(因为父类中没有 Update() 方法,它接受 ProgressBar.UpdateArgs 对象作为参数)。这是可以理解的,例如我可以实现不是从 UIElement.UpdateArgs 派生的 ProgressBar.UpdateArgs 类,这会导致错误和其他东西。

所以我的问题是,我怎样才能以一种聪明的方式实现我上面描述的内容?是否有类似嵌套类的行为,但保证 if A : B then A.nested : B.nested

【问题讨论】:

  • 没有。也许您可以使用泛型,但您需要重新考虑设计或使用重载方法,因为您无法更改虚拟的签名。如果您在重新设计方面需要帮助,您需要使用有关领域、要求、目标和更多代码的更多详细信息来更新问题。
  • 你的设计本身就有缺陷。请参阅 the Circle-ellipse problemLiskov Substitution Principle,您的设计违反了它们。为什么你认为在UIElement 中有这样一个Update 方法是个好主意?你到底想用它做什么?

标签: c# inheritance inner-classes


【解决方案1】:

我建议两种解决方案。

  1. 使用强制类型
    class UIElement
    {
        public virtual void Update(UpdateArgs args) { }

        public class UpdateArgs { }
    }

    class ProgressBar : UIElement
    {
        public override void Update(UpdateArgs args)
        {
            base.Update(args);

            if(args is ProgressBarUpdateArgs updateArgs)
            {
                Console.WriteLine(updateArgs.Progress);
            }
        }

        public class ProgressBarUpdateArgs : UpdateArgs
        {
            public int Progress { get; set; }
        }
    }
  1. 使用通用
    class UIElement<T> // or class UIElement<T> where T: UIElement.UpdateArgs
    {
        public virtual void Update(T args) { }

        public class UpdateArgs { }
    }

    class ProgressBar : UIElement<ProgressBar.ProgressBarUpdateArgs>
    {
        public override void Update(ProgressBarUpdateArgs args)
        {
            base.Update(args);

            Console.WriteLine(args.Progress);
        }

        public class ProgressBarUpdateArgs : UpdateArgs
        {
            public int Progress { get; set; }
        }
    }

这两种解决方案都有效,但您可以根据自己的目的选择一种。抱歉,我无法在这里简短地解释它们是如何工作的,但是如果您有什么要问的,请在下面留言 w

【讨论】:

  • 非常感谢。我想我了解它们的工作原理。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-07-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多