Подтвердить что ты не робот

Необязательные параметры в управляемых методах С++/CLI

Как я могу объявить управляемый метод в С++/CLI, который имеет необязательный параметр при использовании с С#?

Я украсил параметр как Optional и DefaultParameterValue (см. Как кодируются значения параметров по умолчанию), но только атрибут Optional, по-видимому, соблюдается.


С++/CLI:

public ref class MyClass1
{
 public:
  MyClass1([System::Runtime::InteropServices::Optional]
           [System::Runtime::InteropServices::DefaultParameterValue(2)]
           int myParam1)                                            ↑
  {
    System::Console::WriteLine(myParam1);
  }
};

С#:

var myInstance1 = new MyClass1();  // compiles and runs

Вывод:

0

Ожидаемый результат:

2

Visual С# IntelliSense:

MyClass1.MyClass1([int myParam1 = 0]);  // wrong default value
                                  ↑

Изменить: Более пристальный взгляд с дизассемблером показывает, что компилятор С++/CLI действительно не создает требуемую директиву .param [1] = int32(2). Код IL, показанный Reflector, неверен.

Отражатель:

.method public hidebysig specialname rtspecialname instance void .ctor([opt] int32 myParam1) cil managed
{
    .param [1] = int32(2)  // bug
    ...

ILDASM:

.method public hidebysig specialname rtspecialname instance void .ctor([opt] int32 myParam1) cil managed
{
    .param [1]
    .custom instance void [System]System.Runtime.InteropServices.DefaultParameterValueAttribute::.ctor(object) = ( 01 00 08 02 00 00 00 00 00 ) 
    ...
4b9b3361

Ответ 1

Компилятор С# не использует атрибут [DefaultParameterValue] для установки значения по умолчанию, он использует директиву .param для получения значения, встроенного в метаданные. Закономерно только в спецификации CLI, только раздел II, глава 15.4.1 упоминает, что он может иметь значение FieldInit, 15.4.1.4 молчал об этом.

Что, когда buck останавливается, компилятор С++/CLI не знает, как сгенерировать директиву. Вы не можете выполнить эту работу.

Ответ 2

Есть трюк, чтобы сделать эту работу (обходной путь). волшебное слово равно NULL, так как для типов с нулевым значением по умолчанию всегда "null" (.HasValue == false)

Пример:

CLI CLI в заголовке:

String^ test([Optional] Nullable<bool> boolTest);

С++ CLI в .cpp файле:

String^ YourClass::test(Nullable<bool> boolTest)
{
    if (!boolTest.HasValue) { boolTest = true; }
    return (boolTest ? gcnew String("True") : gcnew String("False"));
}

Проверить его на С#:

MessageBox.Show(YourClass.test());

Ответ 3

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