Главная > .NET > MS Visual Studio “Orcas” и новые возможности С#. Часть вторая — методы-расширения

MS Visual Studio “Orcas” и новые возможности С#. Часть вторая — методы-расширения

30 октября 2007

Этой статьёй я продолжаю цикл о новых возможностях C# "Orcas". Предыдущую статью вы можете прочитать здесь.

Итак, методы-расширения. Они позволяют добавлять новые методы к публичной части интерфейса существующего типа без его изменения или создания новых подклассов. Раньше для этого нужно было создавать статический метод, который принимал бы нужный объект как параметр. Теперь нам также нужно создавать статический метод, только выглядит это по-другому:

  1. public static bool In(this object o, IEnumerable c)
  2. {
  3. foreach (object i in c)
  4. {
  5. if (i.Equals(o))
  6. return true;
  7. }
  8. return false;
  9. }

И способ использования:

  1. string[] values = { "alpha", "beta", "release" };
  2. Console.WriteLine("test".In(values));

В этом примере показан пример создания метода-расширения In для объекта типа object (то есть, для каждого объекта CLR). Расширяемый объект указан первым параметром с использованием ключевого слова this. Дальше указываются параметры нового метода. Для меня показалось немного странным то, что функциональность объекта расширяется статическим методом другого объекта. Не скажу что это плохо, но как-то не интуитивно..

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

Производительность. Отличается ли вызов метода расширения от обычного метода? Ответ дает IL-код примера использования:

IL_0027: call bool MyOscarTests.Program::In(object, class [mscorlib]System.Collections.IEnumerable)
IL_002c: call void [mscorlib]System.Console::WriteLine(bool)

Как видно, CLR реально вызывает статический метод, передавая нужный объект как параметр. Так что о производительности можно не волноваться.

Уровень доступ к объекту. А точнее, может ли метод-расширение иметь доступ к защищённым методам и переменным, или только к публичному интерфейсу объекта? Нет, только публичному интерфейсу. Это становится из приведённого више IL-кода - так как объект передаётся в метод другого класса, доступа к защищённым мемберам не будет.

Чистота кода и Code Review. А вот здесь, думаю, будут проблемы. Дело в том что с использованием методы-расширения - очень мощная функциональность, с помощью которой можно удобно «захакать» какую то проблему в архитектуре приложения. Есть подозрения в том что эта возможность будет использоваться слишком часто и без надобности, в место проработки надлежащей иерархии классов, архитектуры. Кроме того, очевидно осложнение для ревью кода, так как теперь становится не совсем понятно, какой метод будет вызван. Например:

  1. public static bool In(this object o, IEnumerable c)
  2. {
  3. ...
  4. }
  5.  
  6. public static bool In(this string o, IEnumerable c)
  7. {
  8. ...
  9. }
  10.  
  11. static void Main(string[] args)
  12. {
  13. string[] values = { "alpha", "beta", "release" };
  14. object obj = "test";
  15. obj.In(values);
  16. }

И какой же метод буде вызван? На самом деле первый. И таких примеров можно придумать достаточно. Чтобы облегчить понимание, что и как будет работать, нужно помнить - решение о том, какой метод нужно будет вызвать, принимается на этапе компиляции, и вызов будет не виртуальным.

Как резюме для этого вопроса - использование методов-расширений нужно строго ограничить стандартами кодирования и допустимой областью использования.

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

Можно ли расширять свойства, операторы. На данное время нет. Хотя это может изменится в будущем.

Это новая фича языка или компилятора? Фактически, методы-расширения реализуются компилятором без использования новых IL-инструкций. Таким образом, можно писать код, используя методы- расширения и компилировать его в VS "Orcas", при этом выбрав в качестве платформы .NET 2.0.

Использование совместно с generics. Это возможно! Можно написать что-то типа:

  1. public static bool In<T>(this T o, IEnumerable<T> c)
  2. {
  3. foreach (T i in c)
  4. {
  5. if (i.Equals(o))
  6. return true;
  7. }
  8. return false;
  9. }

Безусловно, методы-расширения - интересное нововведение. Я описал здесь те моменты которые меня заинтересовали с точки зрения практического девелопмента. Буду рад прочитать в комментах ваши мнения, особенно если кто-то уже использовал эту возможность в реальных проектах.
Анонс.
Тема следующей статьи - анонимные типы (anonymous types) и автореализованные свойства (auto-implemented properties).

  1. Олег
    6 декабря 2007 в 02:20 | #1

    Может все таки Orcas, а не Oscar?

  2. 6 декабря 2007 в 14:03 | #2

    да, точно, сейчас поправлю! спасибо за замечание, просмотрели

Комментирование отключено.
Developers.org.ua