Необязательные параметры в управляемых методах С++/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 )
...
Ответы
Ответ 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 и должен иметь тот же конечный результат, что и значение параметра по умолчанию.