Сложности с необязательными параметрами. Часть 4

(Это четвертая и заключительная часть серии сообщений о сложностях с необязательными параметрами в языке C# 4; третья часть доступна здесь.)

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

void M(string format, bool b = false)
{
Console.WriteLine(format, b);
}

На самом деле является синтаксическим сахаром для следующего кода:

void M(string format, bool? b)
{
  bool realB = b ?? false;
  Console.WriteLine(format, realB);
}

а затем вызов метода:

M("{0}");

заменяется на:

M("{0}", null);

Т.е. они считают, что значение по умолчанию каким-то образом «привязано» к вызываемому коду (callee).

На самом деле, значения по умолчанию привязаны к вызывающему коду (caller); вызываемый код не изменяется, а вызывающий код изменяется следующим образом:

M("{0}", false);

Из этого следует, что если вы измените значение по умолчанию библиотечного метода без перекомпиляции кода, использующего эту библиотеку, то поведение вызываемого кода из-за этого не изменится. Выпуск новой версии метода “M” со значением по умолчанию, равным “true” никак не повлияет на вызываемый код. До тех пор, пока код, вызывающий метод M с одним аргументом не будет перекомпилирован, он всегда будет передавать вторым аргументом “false”.

Это может быть хорошо. Изменение значения по умолчанию с “false” на “true” является ломающим изменением (breaking change) и многие могут возразить, что существующий код, вызывающий метод *должен* быть огражден от этого изменения.

Такое поведение влечет за собой серьезную проблему версионирования, и является одной из главных причин, почему мы так долго откладывали добавление параметров по умолчанию в язык C#. Урок заключается в том, что вы должны тщательно обдумывать сценарии с точки зрения долгосрочной перспективы. Если вы ожидаете будущих изменений значения по умолчанию и хотите, чтобы вызывающий код подхватил эти изменения без перекомпиляции, то не используйте параметры по умолчанию; сделайте две перегружаемые версии метода, когда версия с меньшим числом аргументов будет вызывать другую.

(Это четвертая и заключительная часть серии постов о сложностях с необязательными параметрами в языке C# 4; третья часть доступна здесь.)

Оригинал статьи