Смогут ли абоненты нижнего уровня использовать дополнительные параметры в сборках, созданных с помощью C # 4.0?

2

Предположим, что у меня есть существующая сборка, а некоторые из классов имеют перегруженные методы, с поведением по умолчанию или значениями, принятыми для некоторых из этих перегрузок. Я думаю, что это довольно типичная картина;

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 не будет жаловаться.

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

  • 0
    Ваша идея о том, что компилятор c # создает перегрузки в IL за кулисами, звучит интригующе. Казалось бы, это идеальное решение, поскольку оно не требует специальных знаний со стороны клиентов.
  • 0
    @Robert: Роберт: Это было бы идеально только для решения этой конкретной проблемы, которая, вероятно, не является основной целью дизайна. Это функция C # 4.0, предназначенная для потребителей C # 4.0. Автоматически генерируемые перегрузки также вызывают проблемы. Наличие только 4 необязательных параметров потребует 16 различных перегрузок (от 2 до 4 степени), увеличения размера кода, усложнения разрешения перегрузки и затруднения навигации по значению intellisense. Это также не сработало бы, если бы любые два из этих необязательных параметров были одного типа. Если бы у вас был void Foo (int a = 0, int b = 0), перегрузка не сработала бы для их дифференциации.
Теги:
c#-4.0

3 ответа

1
Лучший ответ

Я не читал документы по новому языковому стандарту, но я бы предположил, что вашим абонентам до 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) должен быть передан дополнительный скрытый параметр, о котором более старые компиляторы даже не знали, если только он не был добавлен как формальный параметр в метаданных.

  • 0
    Так что было бы справедливо сказать, что с Чизо все будет в порядке, если он перекомпилирует своих клиентов в c # 4.0?
  • 0
    Конечно. По дизайну.
Показать ещё 4 комментария
1

В С# 4.0, когда необязательный параметр опущен, значение по умолчанию для этого параметра заменяется на:

public void SendMail(string toAddress, string bodyText, bool ccAdministrator = true, bool isBodyHtml = false)
{ 
    // Full implementation here   
}

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

Ваши существующие вызовы на нижнем уровне должны все еще работать, но вам придется перекомпилировать своих клиентов в С# 4.0.

  • 0
    Итак, вы говорите, что я не могу использовать [необязательные параметры] для рефакторинга моей сборки, если я хочу поддерживать потребителей сборки более низкого уровня, если я не доволен ребятами нижнего уровня, задающими все параметры для каждого вызова метода.
  • 0
    Я уточнил свой ответ. Извините за путаницу.
Показать ещё 9 комментариев
0

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

  • 0
    Не правда. клиенты нижнего уровня не будут работать.
  • 0
    Когда я опубликовал этот ответ, вы не указали, что клиенты нижнего уровня были скомпилированы с .NET 2.0 или 3.5 ... так что это было правдой до того, как вы отредактировали свое сообщение! Пониженное голосование, потому что мой ответ стал неправильным после того, как ваше редактирование кажется немного несправедливым ...
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню