2016-04-08 4 views
1

В настоящее время я изучаю методы расширения C#. Я читал в нескольких местах, что добавление членов в классы уменьшает обратную совместимость для кода, который использует эти классы.Как добавить членов уменьшить обратную совместимость классов?

Я прочитал это здесь: https://blogs.msdn.microsoft.com/vbteam/2007/03/10/extension-methods-best-practices-extension-methods-part-6/

И страница 418 из Pro C# книги Troelson в.

Я боюсь, что это не имеет смысла для меня. Конечно, любой код, который использует экземпляры этих классов по мере их добавления до добавления дополнительных членов (без использования методов расширения, просто добавив их в класс), все равно сможет вызвать все старые методы, свойства, поля и конструкторы, как раньше, поскольку они не изменились. Даже если новые участники могут изменять состояние объекта, они никогда не будут вызываться в старом коде, поэтому код будет обратно совместим.

Что я не вижу здесь?

+1

Вы не видите, как изменение кода, выполняемого, когда данный метод вызывается в экземпляре типа из одной реализации в другую, может каким-то образом повлиять на этот код? – Servy

+0

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

+0

@GeorgeWooding, Добавил второй пример к моему ответу. – devuxer

ответ

2

Вот один из возможных способов добавить новый метод может фактически разрушить код клиента ...

void Main() 
{ 
    var oldFoo = new OldFoo(); 
    var oldResult = oldFoo.Calculate(2, 2); // 4 
    var newFoo = new NewFoo(); 
    var newResult = newFoo.Calculate(2, 2); // 0 
} 

public class OldFoo 
{ 
    public int Calculate(params int[] values) 
    { 
     return values.Sum(); 
    } 
} 

public class NewFoo 
{ 
    public int Calculate(params int[] values) 
    { 
     return values.Sum(); 
    } 

    public int Calculate(int value1, int value2) 
    { 
     return value1 - value2; 
    } 
} 

А вот еще один способ, в частности, имеем дело с методом расширения ...

Первоначально , клиент определяет способ расширения, чтобы дать Foo возможность Combine:

void Main() 
{ 
    var foo = new Foo(); 
    var result = foo.Combine(2, 2); // "22" 
} 

public static class Extensions // added by client 
{ 
    public static string Combine(this Foo foo, params int[] values) 
    { 
     return string.Join(string.Empty, values.Select(x => x.ToString())); 
    } 
} 

public class Foo { } 

Позже, разработчик Foo добавляет новый метод Combine к классу:

void Main() 
{ 
    var foo = new Foo(); 
    var result = foo.Combine(2, 2); // 4 
} 

public static class Extensions 
{ 
    public static string Combine(this Foo foo, params int[] values) 
    { 
     return string.Join(string.Empty, values.Select(x => x.ToString())); 
    } 
} 

public class Foo 
{ 
    public int Combine(params int[] values) 
    { 
     return values.Sum(); 
    } 
} 

Обратите внимание, что метод расширения получает эффективно блокировать или слежка новым методом Combine экземпляра.

-1

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

Добавление нового элемента (топливного насоса) уменьшило обратную совместимость. Конструкция харвестера была основана на версии назад в истории.

И более основанный на программировании пример: дизайнер приложений создает парсер для своего приложения, которое ведет себя определенным образом. После выпуска выяснилось, что парсер не реализует спецификацию правильно для некоторых необычных условий. Выпущена новая версия, которая правильно реализует спецификацию, но добавляет флаг для обеспечения предыдущего поведения.

1

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

Если вы обновите свой класс библиотеки новым методом-членом и ваш клиент установит обновление, он может найти, что ваш новый метод имеет то же имя, что и метод расширения, который он добавил ранее. Или он может не найти его, если списки аргументов совместимы. Его метод расширения теперь будет скрыт вашим новым методом-членом. Его код теперь либо не компилируется (несовместимый список аргументов), либо, что хуже, ведет себя по-другому.

Смежные вопросы