C# 编译器如何区分抽象方法的具体子类实现和抽象基类中的重载?

How does the C# compiler distinguish between a concrete subclass impl of an abstract method and an overload in the abstract base?

如果你有基础class

public abstract class AbsHashtableish<TKey, TValue>
{
    public abstract TKey ConvertToKey(string key);
    public abstract bool KeyExists(TKey key);

    public virtual bool KeyExists(string key)
    {
         Console.WriteLine("In Base");
         return KeyExists(ConvertToKey(key));
    }
}

和一个具体的class

public class ConcreteHashtableish: AbsHashtableish<string, Dinosaur>
{
    ...

    public override string ConvertToKey(string key)
    {
         return key;
    }

    public override bool KeyExists(string key)
    {
         Console.WriteLine("In Sub");
         return _list.Contains(key);
    }
}

和客户A

AbsHashtableish<string, Dinosaur> concreteA = new ConcreteHashtableish<string, Dinosaur>();

和客户 B

ConcreteHashtableish<string, Dinosaur> concreteB = new ConcreteHashtableish<string, Dinosaur>();

确定上面显示的代码是否足以编译的规则是什么(如果可能的话,它们背后的原因)是什么:

  1. concreteAconcreteB 上调用 KeyExists 有区别吗?
  2. 假设我们能以某种方式进入基础 class 方法 KeyExists(string key),我们能从中脱身吗?

对于问题 #2,我的意思是,如果编译器能够以某种方式编译此代码,它是否通过有效地向客户端隐藏基本方法来实现 - 因为如果到达该代码,它会导致在无限循环中?

convreteAconcreteB 上调用 KeyExists 最终是一样的。

Common Language Runtime (CLR) 知道调用实际类型的方法(使用 Virtual Method Table). This is the whole point of Polymorphism。它允许您将具体实现称为抽象实现,但实际调用的方法是具体类型.

在您给出的特定示例中,您不能从派生的 class 外部使用 KeyExists 的基础 class 实现,因为您无法创建实例摘要 class。如果它不是抽象的,您可以创建:

AbsHashtableish<string, Dinosaur> baseA = new AbsHashtableish<string, Dinosaur>();

并且 AbsHashtableish.KeyExists 会被调用。

编辑:(感谢 Oliver 的提醒)

您始终可以从派生 class 内部调用基础 class 实现。在这种情况下,您可以调用:

base.KeyExists(key)