Extensions, Static methods & null

23 окт. 2011 г. | | |

Методы расширения (extension methods), появившиеся ещё в C# 3.0,  - очень полезная штука.
Методы расширения позволяют "добавлять" методы в существующие типы без создания нового производного типа, перекомпиляции или иного изменения исходного типа. Методы расширения являются особым видом статического метода, но они вызываются, как если бы они были методами экземпляра в расширенном типе. (из MSDN)
Т.е. если в классе String нам не хватает какого-нибудь метода, то не нужно создавать еще один класс, наследуясь от String или, чего хуже, делая декоратор, а можно создать метод расширения:

public static class MyExtensions
{
        public static int WordCount(this String str)
        {
            return str.Split(new char[] { ' ', '.', '?' }, 
                             StringSplitOptions.RemoveEmptyEntries).Length;
        }
 }   
(пример тоже из MSDN)
Иногда бывает ситуация, когда нужно вызвать метод расширения в статическом методе класса. Но этого нельзя сделать, несмотря на то, что
Методы расширения являются особым видом статического метода, но они вызываются, как если бы они были методами экземпляра в расширенном типе. (из MSDN)

Но, если всё же очень надо, то есть пара приёмчиков :)

Например, у нас есть класс Document, и в статическом методе Open нам очень хотелось бы вызвать метод расширения Spell().


Как можно вызвать Spell()? Для начала можно создать новый документ и вызвать у него метод расширения, но это не спортивно, тем более проще будет вызвать метод ChangeText().
var text = default(IDocument).Spell(data);
что, в принципе, эквивалентно, следующему:
var text = (null as IDocument).Spell(data);
Что тут происходит? default для ссылочных типов данных - это null, а для value-типов - 0. Т.е. мы вызываем метод Spell() не на объекте, а на null? Почему же не случается Null Reference Exception? Чтобы понять, нужно просто взглянуть на реализацию метода расширения:

Объект document, на котором вызывается метод расширения, будет равен null, и пока мы не попытаемся использовать его без проверки на null, ничего страшного, не произойдёт.
Кстати, используя эту фичу, можно написать расширение для проверки объекта на null, чтобы заменить if (obj == null) ....
Пример использования:

0 коммент.:

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