Предположим, что у меня есть существующая сборка, а некоторые из классов имеют перегруженные методы, с поведением по умолчанию или значениями, принятыми для некоторых из этих перегрузок. Я думаю, что это довольно типичная картина;
Type2 _defaultValueForParam2 = foo;
Type3 _defaultValueForParam3 = bar;
public ReturnType TheMethod(Type1 param1)
{
return TheMethod(param1, _defaultValueForParam2);
}
public ReturnType TheMethod(Type1 param1, Type2 param2)
{
return TheMethod(param1, param2, _defaultValueForParam3);
}
public ReturnType TheMethod(Type1 param1, Type2 param2, Type3 param3)
{
// actually implement the method here.
}
И я понимаю, что необязательные параметры на С# должны позволить мне объединить это до одного метода. Если я создаю метод с некоторыми параметрами, отмеченными как опция, будет ли он работать с абонентами нижнего уровня сборки?
РЕДАКТИРОВАТЬ. Под "work" я имею в виду, что вызывающий нисходящий вызов, приложение, скомпилированное с компилятором С# 2.0 или 3.5, сможет вызывать метод с одним, двумя или тремя параметрами, просто как если бы я использовал перегрузки, а компилятор downlevel не будет жаловаться.
Я хочу реорганизовать и устранить все перегрузки в своей библиотеке, но я не хочу заставлять вызывающих абонентов нижнего уровня использовать рефакторированную библиотеку для предоставления каждого параметра.
Я не читал документы по новому языковому стандарту, но я бы предположил, что вашим абонентам до 4.0 будут переданы объявленные параметры all, как и сейчас. Это связано с тем, как работает параметрирование.
Когда вы вызываете метод, аргументы помещаются в стек. Если три 32-битных аргумента передаются, тогда в стек будет вложено 12 байтов; если четыре 32-битных аргумента передаются, тогда 16 байт будут помещены в стек. Количество байтов, помещенных в стек, неявно в вызове: вызываемый предполагает, что было отправлено правильное количество аргументов.
Итак, если функция принимает четыре 32-битных параметра, она будет смотреть на стек в 16 байтах, предшествующих обратному адресу вызывающего. Если вызывающий абонент пропустил всего 12 байт, то вызываемый будет читать 4 байта того, что уже было в стеке до вызова. Он не знает, что все 16 ожидаемых байтов не были переданы.
Так оно и работает. Там нет изменений для существующих компиляторов.
Чтобы поддерживать необязательные параметры, должно произойти одно из двух:
Я подозреваю, что он будет реализован как в (2) выше. Это похоже на то, как это делается на С++ (хотя С++, лишенный метаданных, требует указания параметров по умолчанию в заголовочном файле), более эффективна эта опция (1), поскольку все это выполняется во время компиляции и не выполняется требуют дополнительного значения для вставки в стек и являются наиболее простой реализацией. Недостатком опции (2) является то, что при изменении значений по умолчанию все вызывающие лица должны быть перекомпилированы, иначе они будут продолжать передавать старые значения по умолчанию, поскольку они были скомпилированы как константы. Это похоже на то, как работают публичные константы. Обратите внимание, что параметр (1) не страдает этим недостатком.
Опция (1) также не поддерживает передачу именованного параметра, в соответствии с которой данная функция объявлена следующим образом:
static void Foo(int a, int b = 0, int c = 0){}
его можно вызвать так:
Foo(1, c: 2);
Вариант (1) может быть изменен, чтобы сделать это, сделав лишнее скрытое значение растровым изображением пропущенных аргументов, где каждый бит представляет один необязательный параметр. Это произвольно ограничивает количество необязательных параметров, которые может принять функция, хотя при условии, что это ограничение будет не менее 32, что может быть не так уж плохо. Однако очень маловероятно, что это фактическая реализация.
Для любой реализации код вызова должен понимать механику необязательных параметров, чтобы опустить любые аргументы в вызове. Кроме того, с опцией (1) должен быть передан дополнительный скрытый параметр, о котором более старые компиляторы даже не знали, если только он не был добавлен как формальный параметр в метаданных.
В С# 4.0, когда необязательный параметр опущен, значение по умолчанию для этого параметра заменяется на:
public void SendMail(string toAddress, string bodyText, bool ccAdministrator = true, bool isBodyHtml = false)
{
// Full implementation here
}
Для ваших абонентов нижнего уровня это означает, что если они используют один из вариантов, которые не имеют параметров, С# заменит значение по умолчанию, которое вы предоставили для отсутствующего параметра. В этой статье более подробно описывается процесс.
Ваши существующие вызовы на нижнем уровне должны все еще работать, но вам придется перекомпилировать своих клиентов в С# 4.0.
Ну, я думаю, что если вы замените все 3 метода одним методом с дополнительными параметрами, код, который использует вашу библиотеку, по-прежнему будет работать, но его нужно будет перекомпилировать.