C# 为什么可以';编译器解析方法是否重写?

C# 为什么可以';编译器解析方法是否重写?,c#,polymorphism,C#,Polymorphism,在下面的C#代码段中 要调用的方法在运行时确定。为什么编译器不知道调用哪个方法 为什么编译器没有看到a引用了Dog对象,然后从该类中选择方法 运行时如何确定要调用哪个方法?您告诉编译器该变量属于Animal类型。它只查看声明,而您希望它执行您的代码来理解您的意思。这不是它的工作原理。您告诉编译器该变量属于Animal类型。它只查看声明,而您希望它执行您的代码来理解您的意思。这不是它的工作原理。这听起来很像一个考试/家庭作业问题。但让我用另一个问题来回答你的问题。 考虑下面的代码: static

在下面的C#代码段中

要调用的方法在运行时确定。为什么编译器不知道调用哪个方法

为什么编译器没有看到
a
引用了
Dog
对象,然后从该类中选择方法


运行时如何确定要调用哪个方法?

您告诉编译器该变量属于Animal类型。它只查看声明,而您希望它执行您的代码来理解您的意思。这不是它的工作原理。

您告诉编译器该变量属于Animal类型。它只查看声明,而您希望它执行您的代码来理解您的意思。这不是它的工作原理。

这听起来很像一个考试/家庭作业问题。但让我用另一个问题来回答你的问题。 考虑下面的代码:

static void Main(string[] args)
{
    var random = new Random();
    Animal an = null;
    if (random.NextDouble() < 0.5) {
      an = new Dog();
    } else {
      an = new Cat();
    }

    an.MakeSound();           
    Console.ReadLine();
}
class Program
{
    static void Main(string[] args)
    {
        Animal dog = new Dog();
        MakeSoundAbstract(dog);

        Animal an = new Animal();
        MakeSoundAbstract(an);

        Console.ReadLine();
    }

    static void MakeSoundAbstract(Animal animal)
    {
        animal.MakeSound();
    }
}
static void Main(字符串[]args)
{
var random=新的random();
动物an=null;
if(random.NextDouble()<0.5){
安=新狗();
}否则{
an=新的Cat();
}
a.MakeSound();
Console.ReadLine();
}

编译器如何在编译时知道调用哪个方法?不能,只有在运行时才知道具体类型。

这听起来很像考试/作业问题。但让我用另一个问题来回答你的问题。 考虑下面的代码:

static void Main(string[] args)
{
    var random = new Random();
    Animal an = null;
    if (random.NextDouble() < 0.5) {
      an = new Dog();
    } else {
      an = new Cat();
    }

    an.MakeSound();           
    Console.ReadLine();
}
class Program
{
    static void Main(string[] args)
    {
        Animal dog = new Dog();
        MakeSoundAbstract(dog);

        Animal an = new Animal();
        MakeSoundAbstract(an);

        Console.ReadLine();
    }

    static void MakeSoundAbstract(Animal animal)
    {
        animal.MakeSound();
    }
}
static void Main(字符串[]args)
{
var random=新的random();
动物an=null;
if(random.NextDouble()<0.5){
安=新狗();
}否则{
an=新的Cat();
}
a.MakeSound();
Console.ReadLine();
}

编译器如何在编译时知道调用哪个方法?不能,只有在运行时才知道具体类型。

考虑以下代码:

static void Main(string[] args)
{
    var random = new Random();
    Animal an = null;
    if (random.NextDouble() < 0.5) {
      an = new Dog();
    } else {
      an = new Cat();
    }

    an.MakeSound();           
    Console.ReadLine();
}
class Program
{
    static void Main(string[] args)
    {
        Animal dog = new Dog();
        MakeSoundAbstract(dog);

        Animal an = new Animal();
        MakeSoundAbstract(an);

        Console.ReadLine();
    }

    static void MakeSoundAbstract(Animal animal)
    {
        animal.MakeSound();
    }
}

如果编译器将在编译期间而不是在运行时确定虚拟调用,则
MakeSoundAbstract
方法将始终执行
MakeSound
类动物的
方法,因此我们在这里失去了。

考虑以下代码:

static void Main(string[] args)
{
    var random = new Random();
    Animal an = null;
    if (random.NextDouble() < 0.5) {
      an = new Dog();
    } else {
      an = new Cat();
    }

    an.MakeSound();           
    Console.ReadLine();
}
class Program
{
    static void Main(string[] args)
    {
        Animal dog = new Dog();
        MakeSoundAbstract(dog);

        Animal an = new Animal();
        MakeSoundAbstract(an);

        Console.ReadLine();
    }

    static void MakeSoundAbstract(Animal animal)
    {
        animal.MakeSound();
    }
}

如果编译器将在编译期间而不是在运行时确定虚拟调用,则
MakeSoundAbstract
方法将始终执行
MakeSound
类动物的方法,因此我们在这里失去了的功能。

请考虑对代码的此更改:

public class Animal
{
  public virtual void MakeSound()
  {
    Console.WriteLine("Animal sound");
  }
}

public class Dog : Animal
{
  public override void MakeSound()
  {
    Console.WriteLine("Woof!");
  }
}

public class Cat : Animal
{
  public override void MakeSound()
  {
    Console.WriteLine("Purrrrrrrrrrrrrr");
  }
}

class Program
{
  static void Main(string[] args)
  {
     Animal an = GetAnimal(DateTime.Now);
     an.MakeSound();           
     Console.ReadLine();
  }

  private Animal GetAnimal(DateTime dateTime)
  {
    if (dateTime.DayOfWeek == DayOfWeek.Monday)
    {
      return new Dog();
    }
    else
    {
      return new Cat();
    }
  }
}

现在不可能知道在编译时创建什么类型的动物,因为这取决于代码实际运行的日期。星期一你会得到一只狗,但在其他任何时候你都会得到一只猫。这是多态性的一个决定性优势——类型不是由编译器烘焙的,而是在代码执行时动态派生的。多态性允许您使用这些派生类型,即使您不知道在编写代码时它们将是什么(但您知道它们都是动物类型)

考虑一下对代码的这种更改:

public class Animal
{
  public virtual void MakeSound()
  {
    Console.WriteLine("Animal sound");
  }
}

public class Dog : Animal
{
  public override void MakeSound()
  {
    Console.WriteLine("Woof!");
  }
}

public class Cat : Animal
{
  public override void MakeSound()
  {
    Console.WriteLine("Purrrrrrrrrrrrrr");
  }
}

class Program
{
  static void Main(string[] args)
  {
     Animal an = GetAnimal(DateTime.Now);
     an.MakeSound();           
     Console.ReadLine();
  }

  private Animal GetAnimal(DateTime dateTime)
  {
    if (dateTime.DayOfWeek == DayOfWeek.Monday)
    {
      return new Dog();
    }
    else
    {
      return new Cat();
    }
  }
}

现在不可能知道在编译时创建什么类型的动物,因为这取决于代码实际运行的日期。星期一你会得到一只狗,但在其他任何时候你都会得到一只猫。这是多态性的一个决定性优势——类型不是由编译器烘焙的,而是在代码执行时动态派生的。多态性允许您使用这些派生类型,即使您不知道在编写代码时它们将是什么(但您知道它们都是动物类型)

你听说过抽象吗?我的回答是“狗的声音”,如果我把它编译起来,我会觉得很好。他们没有问运行时的输出是什么。事实上,他们在实际问题中非常清楚地表明,他们知道在运行时发生了什么。问题是,为什么编译器在编译时不知道
an
Dog
。你听说过抽象吗?我的回答是,如果我编译这个,我觉得很好。他们没有问运行时的输出是什么。事实上,他们在实际问题中非常清楚地表明,他们知道在运行时发生了什么。问题是为什么编译器在编译时不知道
an
Dog