2011-02-11 65 views
27

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

我已经用OptionalDefaultParameterValue属性(请参阅:How default parameter values are encoded)修饰参数,但只有可选属性似乎得到遵守。


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#智能感知:

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

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

反射器:

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

是否有一个原因,过载是行不通的,你的目的是什么? – 2011-02-11 21:38:20

+0

@韦斯P:只是美学原因。当我无法实现这个工作时,我会做重载,但如果可能的话,我更喜欢可选参数。 – dtb 2011-02-11 21:45:31

回答

27

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

这是buck停止的地方,C++/CLI编译器不知道如何生成指令。你无法完成这项工作。

+3

是的,bug,ildasm.exe显示你真正的交易。只有属性存在。这里有一些困惑,因为VB.NET使用了这个属性,它支持很长一段时间的可选参数。你的代码将与VB.NET一起工作;) – 2011-02-11 22:18:54

5

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

8

有一个技巧,使这个工作(解决方法)。 魔字可以为空,作为空类型的默认始终是 “空”(.HasValue == FALSE)

实施例:

C++ CLI在报头:

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

C++ CLI在。CPP文件:

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

测试它在C#:

MessageBox.Show(YourClass.test());