2016-04-27 2 views
0

В следующих C# фрагментПочему метод компилятора не может переопределить?

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

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

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

метод, который можно назвать определяется во время выполнения. Почему точно не может компилятор выяснить, какой метод вызывать?

Почему компилятор не видит, что an относится к объекту Dog, а затем выбрать метод из этого класса?

И как среда выполнения определяет, какой метод будет вызываться?

+0

Вы когда-нибудь слышали об абстракции? –

+0

Mine говорит, что звук собаки, если я скомпилирую это, мне кажется совершенно хорошим – BugFinder

+0

Они не спрашивали, какой результат будет во время выполнения. Фактически, они ясно дали понять в самом фактическом вопросе, что они знают, что происходит во время выполнения. Вопрос в том, почему компилятор не знает, что '' '' 'Собака' во время компиляции. – Nick

ответ

0

Вы сказали компилятору, что переменная имеет тип Animal. Он выглядит только на объявлениях, в то время как вы ожидаете, что он выполнит ваш код, чтобы понять, что вы имеете в виду. Это не так, как это работает.

3

Это звучит очень много, как вопрос об экзамене/домашнем задании. Но позвольте мне ответить на ваш вопрос другим вопросом. Рассмотрим следующий код:

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(); 
} 

Как компилятор должен знать, во время компиляции, какой метод вызвать? Он не может, только во время работы известен конкретный тип.

0

Рассмотрим следующий код:

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 метод class Animal таким образом мы теряем здесь власть abstraction.

0

Рассмотрим эти изменения в код:

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(); 
    } 
    } 
} 

Теперь это невозможно знать, какой тип животного, чтобы создать во время компиляции, так как это зависит от дня недели, когда код на самом деле запустить. По понедельникам вы получите собаку, но в любой другой момент вы получите кота. Это определяющее преимущество полиморфизма - типы не запекаются компилятором, а производятся на лету, когда выполняется код. Полиморфизм позволяет работать с этими производными типами, даже если вы точно не знаете, что они будут, когда вы пишете свой код (но вы знаете, что это все виды животных).