C#虚方法覆盖返回类型&;方法参数

C#虚方法覆盖返回类型&;方法参数,c#,polymorphism,virtual,overriding,C#,Polymorphism,Virtual,Overriding,我想在抽象类中使用确切的名称初始化虚拟方法 在类中,这是继承器重写方法,因此我可以重写: 基本方法的返回类型 方法的参数 为了向大家展示,我真正想做的是这样的smth: abstract class A { public virtual void Func1() { } } class B : A { override string Func1(int a, int b) { return (a + b).ToString(); } }

我想在抽象类中使用确切的名称初始化虚拟方法

在类中,这是继承器重写方法,因此我可以重写:

  • 基本方法的返回类型
  • 方法的参数
为了向大家展示,我真正想做的是这样的smth:

abstract class A
{
    public virtual void Func1() { }
}

class B : A
{
    override string Func1(int a, int b)
    {
         return (a + b).ToString();
    }
}

我知道,C#需要像在基类中一样使用返回类型/args,但是在这种情况下,可能会有一些关于关键字
new
的提示?

您只能
重写
确切的名称和参数。你可以
new
任何你想要的,但那不是覆盖——只是隐藏在精确匹配的情况下

我认为在您的情况下,您可能需要为所有可能的组合创建重载,或者创建一个单一的基抽象方法,该方法采用一种类型,可以包含您想要的参数

例如:

public abstract void Func1( MyArgumentsType input );
现在,派生类被迫重写一个方法,但您可以将一组健壮的参数传递给该方法,该方法可以处理更多的场景


多态性在这里对您有利,因为您可以将派生参数类型传递给具有特定情况属性的方法。当然,这需要实现方法来理解更派生的参数类型。

您不能这样做。重写方法需要具有完全相同的签名,其中包括参数和返回类型。您无法告诉编译器使用不同的参数和返回类型重写方法

如果你想要多态行为,你需要有兼容的签名。否则,编译器无法保证所需的方法将以多态方式找到


对于签名
void Func1()
string Func1(int a,int b)
,没有一种简单的方法可以将其视为多态的。您可以使用pass lambdas inside的
out
参数对它们进行泛化,但无论如何,要利用多态行为,您需要将它们带到一个公共签名

方法重写意味着修改继承成员的虚拟实现,而不是它的签名。正如您所指出的,
new
关键字将隐藏同名成员的基类实现。但是它只是可选的,看看这个

它看起来像是要实现类似于
ToString
方法的行为,对于不同的类型有许多不同的风格(比如
.ToString()
float.ToString(“c”)

在这种情况下,
ToString
的不同实现不是
Object.ToString
的实现,而是基于参数适当解析的派生对象上的正常附加方法。所有派生类都以一个虚拟的
ToString
方法(来自基类,可能在当前类中实现)和其他非虚拟的类似命名方法结束


请注意,在C#中,函数解析时间会考虑较新的结果类型,因此您不可能真正拥有两个具有相同名称和相同参数的函数,并期望“正确”选择其中一个。如果两者同时可见,则会出现编译时错误<方法前面的code>new
关键字仅使该类(和派生类)可见该方法,并隐藏具有相同签名的基类方法。不幸的是,当一个人使用持有派生类的基类变量来调用这个方法时,这样做会导致很多混乱——尽管尽了一切努力隐藏了一个方法,基类中的虚拟方法还是会被调用。

想想看……它将如何工作?假设您有一个静态类型为
A
但动态类型为
B
的引用,如下所示:

foo(B b) { bar(b); }
bar(A a) { 
}
重写背后的思想是在super/base上调用一个方法,它将解析为被重写的实现。根据该逻辑,您应该能够在
bar
中调用
a.Func1()
,并且它应该调用
B
中的方法:

a.Func1(???)
但由于缺少参数,此处不可能这样做。


有参数逆变换和返回型协方差的概念;在SO中是一个有趣的答案,带有Eric Lippert的帖子链接,应该是一个有趣的阅读。

是的,有一个关键字
new
,但它不是覆盖,只是隐藏一个成员。B.Func1不是覆盖,而是重载。所以你没有重写你不能使用新的、静态的或虚拟的修饰符来修改重写方法。那么继承有什么意义呢?@42多态点+1表示“混乱”…我发现
new
很少是个好主意。可能是通过与中相同的机制:F#,Lisp,Haskell。因为他们实现了,但是有一些动态类型。真正的C#随着他自己的每个版本变得越来越有活力。看看我在这个问题开始时对Servy评论的回答。你是说在这些其他语言中使用完全不同的签名进行覆盖吗?是的,我已经告诉过你了。这些动态语言在使用方法签名时使用了不同的机制。在
C#
中,您如何期望这种工作?例如,在我的示例中,您认为可以用什么替换
,并将调用调度到
B.Func1
?如果
a
的动态类型不接受这些参数,这会是运行时错误吗?是!你是对的。在这些语言中使用这种技术可能会捕获运行时错误,但也可能无法捕获。这完全取决于你。