В этой статье мы рассмотрим различия между точками расширения, созданными с помощью наследования и с помощью делегатов в 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, и вызов такого делегата вызовет исключение NullReferenceException:
Animal animal = new Animal();
animal.Voice(); // Возникнет исключение NullReferenceException
Чтобы избежать такого исключения, перед вызовом делегата мы должны проверить его на null:
Animal animal = new Animal();
if (animal.Voice != null)
{
animal.Voice();
}
Теперь мы можем быть уверены, что делегат не содержит значения null перед его выполнением.
В заключение, наследование и делегаты предоставляют различные подходы к созданию точек расширения в C#/.NET. Наследование предоставляет доступ к базовому поведению, позволяя его изменить и расширить. Делегаты позволяют передавать ссылки на методы и выполнить их в нужном контексте. Учитывайте возможность содержания значения null в делегатах и всегда проверяйте их перед вызовом.