子 classes 中的 C# 方法是否可以具有不同的参数类型(派生自父 class 中方法的参数类型)?

Can C# methods in child classes have different argument type (that derives from an argument type for a method in parent class)?

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

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;
    }
}

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

所以我的问题是,我怎样才能巧妙地实现上面描述的内容?是否有一些行为类似于嵌套 classes,但保证 if A : B then A.nested : B.nested?

我建议两种解决方案。

  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