Сложности с необязательными параметрами. Часть 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; третья часть доступна здесь.)