Различия точек расширения: наследование vs делегаты в C#/.NET

Различия точек расширения: наследование vs делегаты в C#/.NET
Различия точек расширения: наследование vs делегаты в C#/.NET - maxvdo @ Unsplash

В этой статье мы рассмотрим различия между точками расширения, созданными с помощью наследования и с помощью делегатов в C#/.NET. Наследование предоставляет доступ к базовому поведению, в то время как делегаты этого не делают. Кроме того, делегаты могут потенциально содержать значение null.

Точки расширения с использованием наследования

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

Например, у нас есть базовый класс Animal с методом Voice(), который печатает звук, издаваемый животным:

public class Animal
{
    public virtual void Voice()
    {
        Console.WriteLine("I am an animal");
    }
}

Теперь мы можем создать класс-наследник Cat, который будет расширять функционал базового класса Animal:

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

Теперь у нас есть возможность использовать функционал родительского класса Animal и добавить свои собственные изменения. Например, мы можем создать экземпляр класса Cat и вызвать метод Voice():

Animal cat = new Cat();
cat.Voice(); // Выведет "Meow"

Точки расширения с использованием делегатов

Теперь давайте рассмотрим точки расширения, созданные с помощью делегатов. Делегат представляет собой ссылку на метод и позволяет передавать ее в другие методы для их выполнения.

Для создания делегата нам необходимо определить тип делегата и выбрать метод, который мы хотим передать. Например:

public delegate void VoiceDelegate();

public class Animal
{
    public VoiceDelegate Voice { get; set; }
}

Теперь мы можем создать экземпляр класса Animal и передать метод в делегат Voice:

Animal animal = new Animal();
animal.Voice = Meow;

public void Meow()
{
    Console.WriteLine("Meow");
}

При вызове метода Voice() у нашего объекта Animal будет вызван переданный метод Meow:

animal.Voice(); // Выведет "Meow"

Потенциальное значение null в делегатах

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

Это означает, что если делегат не указывает на какой-либо метод, он будет содержать значение null, и вызов такого делегата вызовет исключение NullReferenceException:

Animal animal = new Animal();
animal.Voice(); // Возникнет исключение NullReferenceException

Чтобы избежать такого исключения, перед вызовом делегата мы должны проверить его на null:

Animal animal = new Animal();
if (animal.Voice != null)
{
    animal.Voice();
}

Теперь мы можем быть уверены, что делегат не содержит значения null перед его выполнением.

В заключение, наследование и делегаты предоставляют различные подходы к созданию точек расширения в C#/.NET. Наследование предоставляет доступ к базовому поведению, позволяя его изменить и расширить. Делегаты позволяют передавать ссылки на методы и выполнить их в нужном контексте. Учитывайте возможность содержания значения null в делегатах и всегда проверяйте их перед вызовом.


LetsCodeIt, 14 августа 2023 г., 15:39

Похожие посты

Использование POST для передачи идентификаторов в маршрутах API: философский вопросКлассы Button и Textbox в Selenium: абстракции для взаимодействия с элементами пользовательского интерфейсаНадежная и быстрая обработка сообщений AMPQ в RabbitMQ без потери функций или шаблоновДекларация методов в .NET Core EF: рекомендации и возможные решенияОбновление предупреждающих операторов в подклассах: новый метод с списком предупрежденийПроектирование шлюза API с использованием паттерна конвейера: добавление дополнительного поля для условий неудачного ответаВзаимосвязь дочерних и родительских компонентов в React не осуществляется посредством наследования. Используйте композицию для включения дочерних компонентов внутри родительского компонентаПравило подстановки Лисков в объектно-ориентированном программировании (ООП)Реализация полиморфизма в Java с помощью примера класса Person и MarriedPersonНаследование без полиморфизма/переопределения - правильная практика?