Страницы

Поиск по вопросам

четверг, 28 ноября 2019 г.

Безопасность использования методов расширения

#c_sharp #методы


Как я понимаю, методы самого класса в приоритете перед методами расширения.

Возникает закономерный вопрос:

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

Получается, методы расширения — это опасная штука?

Вот пример:

public class Person
{
    public void Say()
    {
        Console.WriteLine("1");
    }
}

public static class Test
{
    public static void Say(this Person p)
    {
        Console.WriteLine("2");
    }
}

class Program
{         
    static void Main(string[] args)
    {
        var t = new Person();
        t.Say();
    } 
}


Допустим, мы реализовали метод Say в виде расширения и он выводил нам 2, затем приходит
обновление либы и тут бац и выводится 1. Никаких предупреждений компилятор не выдает,
хотя он выдает предупреждение в том случае если мы наследуемся и объявляем метод с
такой же сигнатурой и он просит написать new.

Еще забавно, что нельзя контролировать вызов конкретного метода-расширения, если
есть пересечения между пространствами имен. В этом случае единственный вариант- это
вызов через статику, что убивает удобство использования расширений.
    


Ответы

Ответ 1



Получается, методы расширения — это опасная штука? Да, это несомненно так. Методы расширения — грубый хак, нарушающий принципы объектно-ориентированного программирования, и помимо проблемы неконтролируемого скрытия членами расширяемого класса они также страдают от проблемы конфликтов между самими собой (ведь разные библиотеки могут создавать методы расширения для одного класса). Чрезмерно использовать их не стоит. Framework Design Guidelines явно не рекомендуют это: AVOID frivolously defining extension methods, especially on types you don’t own. Там же упоминают два случая, когда использование методов расширения оправдано: Добавление какого-либо функционала во все типы, реализующие определенный интерфейс. В этом случае опасность несколько ниже, ведь в интерфейсы обычно не добавляют новые методы (так как это требовало бы переписывания кода кучи классов, которые уже реализуют этот интерфейс). Именно таким образом работает LINQ. Методы, завязанные на типы, определенные в вашем собственном коде. Допустим, вы создаете метод расширения к классу String, принимающий аргумент типа Person, определенного в вашем проекте. В этом случае описанного конфликта также не будет, ведь даже если MS добавят новый метод в класс String, он точно никак не будет использовать класс из вашего кода. К сожалению, следование этим рекомендациям все равно полностью не решает проблемы, так как остаются конфликты между самими методами расширений из разных библиотек. Именно с этой проблемой столкнулись разработчики библиотеки MoreLinq. Конечно, Framework Design Guidelines — это рекомендации для разработчиков публичных API библиотек, а не любого кода в приложениях. Но сути это мало меняет, так как нужно стремиться делать любой код пригодным к повторному использованию. Проекты имеют тенденцию расти, разделяться и т.п; какой-то код, который раньше использовался только в одном проекте, впоследствии захочется вынести в общую библиотеку. Поэтому эти рекомендации во многом можно распространить и на код приложений.

Комментариев нет:

Отправить комментарий