为什么这两种方法不含糊
本文关键字:不含糊 方法 两种 为什么 | 更新日期: 2023-09-27 18:03:07
这是ApiController
:中Ok()
方法的签名
protected internal virtual OkResult Ok();
这是我的RestController
类(从ApiController
扩展而来(中的方法:
// Note that I'm not overriding base method
protected IHttpActionResult Ok(string message = null);
由于OkResult
实现了IHttpActionResult
,所以这两种方法都可以这样调用:
IHttpActionResult result = Ok();
事实上,这就是我在应用程序中所做的。
我的类PersistenceRestController
(从RestController
扩展而来(有以下几行代码:
protected override async Task<IHttpActionResult> Delete(Key id)
{
bool deleted = //... Attempts to delete entity
if(deleted) return Ok();
else return NotFound();
}
这编译得很好,并且不会对方法的模糊性发出任何警告。为什么?
PersistenceRestController
还继承了ApiController
的受保护方法,因此它应该同时拥有Ok()
的两个版本(而且确实如此(。
在执行时,执行的方法是来自我的RestController
的方法。
编译器如何知道要运行哪种方法?
当编译器有两个相等的选项可供选择时,它将使用一个重载,该重载不需要使用任何未应用的可选参数,而需要使用。。。
然而,在您的情况下,之所以选择RestController
中的方法,是因为它是派生性更强的类。Jon在他的书《深度C#》中很好地详细阐述了这个主题——看看该页的继承部分,它本质上表明编译器更喜欢实际实例类上的方法,而不是派生较少的类的方法。
编辑:
我将把我最初的答案留给子孙后代,因为我认为它可以让你想象事物,但不要困惑!编译器实际上并没有将可选参数视为重写方法的语法糖。它将其视为具有可选参数的单个方法。Dusty的回答是正确的,他提到"之所以选择RestController中的方法,是因为它是更派生的类"。
ORIGINAL(带有可见的正确编辑(:
因为它们并不含糊。为了避免歧义,方法需要具有相同的签名。string message
参数的默认值为null这一事实有效地创建了BEHAVES,就好像它创建了两个可调用的重写一样,其中一个隐藏原始方法,另一个可以用字符串明显调用。
您正在有效地执行,创建与您要执行此操作相同的行为:
public class RestController : ApiController
{
protected new OkResult Ok()
{
return Ok(null);
}
protected OkResult Ok(string message)
{
// Do your thing...
}
}
您会发现没有办法直接从PersistenceRestController调用ApiController.Ok((。
如果你想从RestController调用ApiController.Ok((,你必须使用base keywoard:base。Ok((;
虽然@DimitarTsonev和@Dusty说的是实话,但你的答案介于他们的答案之间。在这里,您有继承情况。参见以下类别:
public class Foo {
public void Bar() {
}
}
public class Foo2 : Foo{
public void Bar(string message = null) {
}
}
public class Foo3 : Foo2{
public void Test(){
Bar();
}
}
当您在Foo3
类中调用Bar()
时,运行时将查找Foo3
类中的方法。如果找到它,请执行它,否则转到顶级类:Foo2
并查找Bar
方法。有吗?对所以执行吧!这就是为什么当您调用Ok
时,您的RestController
的版本会被执行。
但同时,Foo2.Bar(string message = null)
不会与Foo.Bar()
冲突,因为它们并不像@DimitarTsonev所说的那样模棱两可。因此,您的代码将正常工作。
AND,从Foo3
调用Foo.Bar()
怎么样?你必须在这里使用铸造:
public class Foo3 : Foo2 {
public void Test() {
Bar(); // this will execute Foo2.Bar()
}
public void Test2() {
((Foo)this).Bar(); // this one will execute Foo.Bar()
}
}
public class Foo
{
public void Bar()
{
}
public void Bar(string message = null)
{
}
}
这是两种不同的方法,因为第二种方法具有可选参数。
但是,请注意,不带参数调用的第二个方法实际上会执行第一个方法,这可能会产生一些意外行为