托管C ++ / CLI方法中的可选参数

当在C#中使用时,如何在C ++ / CLI中声明具有可选参数的托管方法?

我使用Optional和DefaultParameterValue属性修饰了参数(请参阅: 如何编码默认参数值 ),但只有Optional属性才被尊重。


C ++ / CLI:

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

C#:

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

输出

 0 

预期产出:

 2 

Visual C#IntelliSense:

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

编辑:仔细观察反汇编程序会发现C ++ / CLI编译器确实没有生成所需的.param [1] = int32(2)指令。 Reflector显示的IL代码是错误的。

reflection:

 .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 ) ... 

C#编译器不使用[DefaultParameterValue]属性来设置默认值,它使用.param指令来获取元数据中嵌入的值。 在CLI规范btw中,只有Partition II,第15.4.1章提到它可以有一个FieldInit值,15.4.1.4对此保持沉默。

这就是降压停止的地方,C ++ / CLI编译器不知道如何生成指令。 你无法做到这一点。

有一个技巧可以使这个工作(解决方法)。 神奇的单词是可空的,对于可空类型,默认值始终为“null”(。HasValue == false)

例:

标头中的C ++ CLI:

 String^ test([Optional] Nullable boolTest); 

.cpp文件中的C ++ CLI:

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

在C#中测试它:

 MessageBox.Show(YourClass.test()); 

作为一种解决方法,您可以重载构造函数,并使用委托。 它将由JIT内联,并且应该以与默认参数值相同的最终结果结束。