访问覆盖的方法 [英] Access to overridden methods

查看:70
本文介绍了访问覆盖的方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有一个练习"OverloadResolutionOverride"

以下代码的输出是什么:

What will be the output of the following code:

class Foo
{
  public virtual void Quux(int a)
  {
    Console.WriteLine("Foo.Quux(int)");
  }
}
class Bar : Foo
{
  public override void Quux(int a)
  {
    Console.WriteLine("Bar.Quux(int)");
  }
  public void Quux(object a)
  {
    Console.WriteLine("Bar.Quux(object)");
  }
}
class Baz : Bar
{
  public override void Quux(int a)
  {
    Console.WriteLine("Baz.Quux(int)");
  }
  public void Quux<T>(params T[] a)
  {
    Console.WriteLine("Baz.Quux(params T[])");
  }
}
void Main()
{
  new Bar().Quux(42);
  new Baz().Quux(42);
}

答案是:

Bar.Quux(object)
Baz.Quux(params T[])

该网站上有一个解释:

如果编译器为方法找到合适的签名 在当前"类中调用时,编译器将不会向父母求助 课.

If compiler found a suitable signature for a method call in the "current" class, compiler will not look to parents classes.

是否认为重载的Quux(int)方法在基类中,而不在当前类中?如果是这样,我如何才能在当前类中准确调用Quux(int)方法?

Is it considered that the overloaded Quux(int) method is in the base class, and not in the current one? If so, how i can call exactly Quux(int) method in current class?

推荐答案

对于编译器进行方法解析时发生的情况,这绝对是一个有趣的效果.

This is definitely an interesting effect of what happens when the compiler does its method resolution.

我们转到规范,看看我们能从中学到什么(这是我的理解,我绝不是阅读规范的专家,所以如果我做错了,请告诉我!).

Let's go to the specification and see what we can get out of that (This is my understanding and I am by no means an expert in reading the specification, so if I got something wrong, please let me know!).

第一步是查找具有

The first step is to find methods that have parameters that are Applicable with the first bullet reading:

A中的每个参数[其中A是参数列表]对应于函数成员中的参数 相应参数中所述的声明,以及任何 没有参数对应的参数是可选参数.

Each argument in A [Where A is the argument list] corresponds to a parameter in the function member declaration as described in Corresponding parameters, and any parameter to which no argument corresponds is an optional parameter.

所以现在我们去看看相应的参数是,我们得到:

So now we go check out what a Corresponding parameter is and we get:

对于在类中定义的虚拟方法和索引器,参数 列表是从最具体的声明或替代中选择的 函数成员,从接收者的静态类型开始,以及 搜索其基类.

For virtual methods and indexers defined in classes, the parameter list is picked from the most specific declaration or override of the function member, starting with the static type of the receiver, and searching through its base classes.

我们也有

对于所有其他函数成员和委托,只有一个 参数列表,这就是使用的列表.

For all other function members and delegates there is only a single parameter list, which is the one used.

因此,对于类Bar,我们找到了两种符合要求的方法:

Therefore, for the class Bar, we find two methods the fit the bill:

  1. Bar.Quux(object).这来自第二段,因为它是直接在类型上定义的.
  2. Foo.Quux(int).这是从派生类型开始的,方法是遵循重写直到virtual方法声明.
  1. Bar.Quux(object). This is from the second paragraph because it is defined on the type directly.
  2. Foo.Quux(int). This is from the derived type by following the override up to the virtual method declaration.

对于Baz类,我们得到3:

  1. Baz.Quux(int[]).这是在类型上定义的.
  2. Bar.Quux(object).这是在父类中定义的,并且在Baz的范围内可见.
  3. Foo.Quux(int).这是覆盖的虚拟声明.
  1. Baz.Quux(int[]). This is defined on the type.
  2. Bar.Quux(object). This is defined in a parent class and is visible to the scope of Baz.
  3. Foo.Quux(int). This is the virtual declaration of the override.

这使我们在Bar中有2种方法匹配,在Baz中有3种可能的方法匹配.这意味着我们需要使用下面的下一个参数集(Emphasis mine)对参数集进行进一步的剔除:

This gives us 2 method matches in Bar, and 3 possible method matches in Baz. This means we need to do further culling of the parameter set with the following next set (Emphasis mine):

候选方法集减少为仅包含来自 最派生的类型:对于集合中的每个方法C.F,其中C是 声明方法F的类型,所有以基声明的方法 类型的C已从集合中删除.此外,如果C是类类型 除了对象,在接口类型中声明的所有方法都是 从集合中删除. (仅当 方法组是对类型参数进行成员查找的结果 具有除对象和非空之外的有效基类 有效的界面集.)

The set of candidate methods is reduced to contain only methods from the most derived types: For each method C.F in the set, where C is the type in which the method F is declared, all methods declared in a base type of C are removed from the set. Furthermore, if C is a class type other than object, all methods declared in an interface type are removed from the set. (This latter rule only has affect when the method group was the result of a member lookup on a type parameter having an effective base class other than object and a non-empty effective interface set.)

因此,对于Bar,我们将剔除Foo.Quux(int),因为它是以基本类型声明的,因此已从集合中删除.

Therefore, for Bar, we will cull Foo.Quux(int) because it is declared in a base type and is therefore removed from the set.

对于Baz,我们删除了以下两个方法,因为它们都是在基本类型中声明的:

For Baz, we remove the following two methods because they are both declared in base types:

  1. Bar.Quux(object)
  2. Foo.Quux(int)
  1. Bar.Quux(object)
  2. Foo.Quux(int)

现在,每个集合只有一个方法,我们可以执行两个方法Bar.Quux(object)Baz.Quux<int>(int[]).

Now, each set has only one method, and we can execute the two methods Bar.Quux(object) and Baz.Quux<int>(int[]).

所以这引出了一个问题,我们可以强制调用正确的方法吗?根据第二个解析步骤(它使用的是派生的类型最多),答案是可以.

So this begs the question, can we force the correct method to be called? And based on the second resolution step, where it uses the most derived type, the answer is that yes we can.

如果要调用Foo的方法,则需要将调用方的类型设置为Foo.如果要Baz调用Bar的方法,则需要将Baz设置为Bar.

If we want to call Foo's methods, we need to set the type of our caller to Foo. If we want Baz to call Bar's method, then we will need to set Baz to Bar.

考虑以下方法调用集:

new Bar().Quux(42);
new Baz().Quux(42);
((Foo)new Bar()).Quux(42);
((Foo)new Baz()).Quux(42);
((Bar)new Baz()).Quux(42);

我们得到以下输出:

Bar.Quux(object)
Baz.Quux(params T[])
Bar.Quux(int)
Baz.Quux(int)
Bar.Quux(object)

并且能够使用与上面类似的方法分辨率来确定我们要使用的特定方法.

And are able to target the specific methods that we want to using a similar method resolution as above.

如果我们将Baz的定义更改为:

If we change the definition of Baz to be following:

class Baz : Bar
{
  public override void Quux(int a)
  {
    Console.WriteLine("Baz.Quux(int)");
  }
}

然后进行方法调用:new Baz().Quux(42);我们的输出仍然是:Bar.Quux(object).由于我们直接在Baz中定义了方法重写,因此这似乎很奇怪.但是,该方法的原始类型是Foo,它比Bar特定.因此,当我们匹配参数列表时,由于int参数列表是在Foo上定义的,因此我们以Bar.Quux(object)Foo.Quux(int)结尾.因此,Foo.Quux(int)在第二步中被剔除,因为BarFoo派生得多,因此我们将其称为Bar.Quux(object).

And then make the method call: new Baz().Quux(42); our output is still: Bar.Quux(object). This seems strange because of the fact that we have a method override defined within Baz directly. However, the originating type for the method is Foo which is less specific than Bar. So when we match our parameter lists, we end up with Bar.Quux(object) and Foo.Quux(int) since the int parameter list is defined on Foo. Therefore, Foo.Quux(int) is culled in the second step since Bar is more derived than Foo, and we call Bar.Quux(object).

我认为这里故事的寓意是不要使用与覆盖相同的命名方法!

I think the moral of the story here is don't name methods the same as overrides!

这篇关于访问覆盖的方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆