Looking for c# Keywords? Try Ask4Keywords

C# Language виртуальный, переопределить, новый


пример

виртуальный и переопределить

Ключевое слово virtual позволяет переопределять метод, свойство, индексор или событие с помощью производных классов и текущего полиморфного поведения. (Члены по умолчанию не являются виртуальными в C #)

public class BaseClass
{
    public virtual void Foo()
    {
        Console.WriteLine("Foo from BaseClass");
    }
}

Для переопределения члена ключевое слово override используется в производных классах. (Обратите внимание, что подпись членов должна быть одинаковой)

public class DerivedClass: BaseClass
{
    public override void Foo()
    {
        Console.WriteLine("Foo from DerivedClass");
    }
}

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

Короче говоря, объект может быть объявлен типа BaseClass во время компиляции, но если во время выполнения это экземпляр DerivedClass тогда будет выполнен переопределенный элемент:

BaseClass obj1 = new BaseClass();
obj1.Foo(); //Outputs "Foo from BaseClass"

obj1 = new DerivedClass();
obj1.Foo(); //Outputs "Foo from DerivedClass"    

Переопределение метода необязательно:

public class SecondDerivedClass: DerivedClass {}

var obj1 = new SecondDerivedClass();
obj1.Foo(); //Outputs "Foo from DerivedClass"    

новый

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

public class BaseClass
{
    public void Foo()
    {
        Console.WriteLine("Foo from BaseClass");
    }
}

public class DerivedClass: BaseClass
{
    public void Foo()
    {
        Console.WriteLine("Foo from DerivedClass");
    }
}

BaseClass obj1 = new BaseClass();
obj1.Foo(); //Outputs "Foo from BaseClass"

obj1 = new DerivedClass();
obj1.Foo(); //Outputs "Foo from BaseClass" too!    

Когда это происходит, выполняемый элемент всегда определяется во время компиляции в зависимости от типа объекта.

  • Если объект объявлен типа BaseClass (даже если во время выполнения имеет производный класс), то выполняется метод BaseClass
  • Если объект объявлен типа DerivedClass тогда выполняется метод DerivedClass .

Обычно это случайность (когда член добавляется к базовому типу после того, как идентичный был добавлен к производному типу), и в этих сценариях генерируется предупреждение CS0108 компилятора.

Если это было намеренно, то new ключевое слово используется для подавления предупреждения компилятора (и сообщите другим разработчикам о ваших намерениях!). поведение остается неизменным, new ключевое слово просто подавляет предупреждение компилятора.

public class BaseClass
{
    public void Foo()
    {
        Console.WriteLine("Foo from BaseClass");
    }
}

public class DerivedClass: BaseClass
{
    public new void Foo()
    {
        Console.WriteLine("Foo from DerivedClass");
    }
}

BaseClass obj1 = new BaseClass();
obj1.Foo(); //Outputs "Foo from BaseClass"

obj1 = new DerivedClass();
obj1.Foo(); //Outputs "Foo from BaseClass" too! 

Использование переопределения не является необязательным

В отличие от C ++, использование ключевого слова override не является необязательным:

public class A
{
    public virtual void Foo()
    {
    }
}

public class B : A
{
    public void Foo() // Generates CS0108
    {
    }
}

Приведенный выше пример также вызывает предупреждение CS0108 , потому что B.Foo() не автоматически переопределяет A.Foo() . Добавить override когда намерение переопределить базовый класс и вызвать полиморфное поведение, добавить new когда вы хотите неполиморфное поведение и разрешить вызов с использованием статического типа. Последнее следует использовать с осторожностью, так как это может вызвать серьезную путаницу.

Следующий код даже приводит к ошибке:

public class A
{
    public void Foo()
    {
    }
}

public class B : A
{
    public override void Foo() // Error: Nothing to override
    {
    }
}

Производные классы могут вводить полиморфизм

Следующий код является абсолютно допустимым (хотя и редким):

    public class A
    {
        public void Foo()
        {
            Console.WriteLine("A");
        }
    }

    public class B : A
    {
        public new virtual void Foo() 
        {
            Console.WriteLine("B");
        }
    }

Теперь все объекты со статической ссылкой B (и ее производных) используют полиморфизм для разрешения Foo() , а ссылки A используют A.Foo() .

A a = new A();
a.Foo(); // Prints "A";
a = new B();
a.Foo(); // Prints "A";
B b = new B();
b.Foo(); // Prints "B";

Виртуальные методы не могут быть частными

Компилятор C # строг в предотвращении бессмысленных конструкций. Методы, помеченные как virtual не могут быть частными. Поскольку частный метод не может быть замечен из производного типа, он не может быть перезаписан. Это не скомпилируется:

public class A
{
    private virtual void Foo() // Error: virtual methods cannot be private
    {
    }
}