在托管C ++ / CLI方式可选参数可选、参数、方式、CLI

2023-09-03 01:20:02 作者:因为当夜深人静的时候,他不知道一个人会发生什么事,

我如何申报C ++ / CLI有管理的方法,有一个可选的参数从C#中使用时?

我饰既是Optional和DefaultParameterValue属性(参见:How默认参数值都设有codeD ),但只有可选属性似乎兑现。

C ++ / CLI:的

 公开引用类MyClass1的
{
 上市:
  MyClass1的([系统::运行:: InteropServices ::可选]
           [系统::运行:: InteropServices :: DefaultParameterValue(2)]
           INT myParam1)↑
  {
    系统::控制台:的WriteLine(myParam1);
  }
};
 

C#:的

  VAR myInstance1 =新MyClass1的(); //编译并运行
 

输出的:

  0
 
云开发静态网站托管现已支持 Angular 应用

预计输出:的

  2
 

的Visual C#智能感知:的

  MyClass1.MyClass1([INT myParam1 = 0]); //错误的默认值
                                  ↑
 

编辑:仔细一看有一个反汇编显示,C ++ / CLI编译器确实不能生成所需的 .PARAM [1] = INT32(2)指令。通过反射显示的IL code是错误的。

反射器:的

 。方法公开hidebysig specialname rtspecialname实例无效.ctor([优化] INT32 myParam1)CIL管理
{
    .PARAM [1] = int32类型(2)//错误
    ...
 

ILDASM:的

 。方法公开hidebysig specialname rtspecialname实例无效.ctor([优化] INT32 myParam1)CIL管理
{
    .PARAM [1]
    .custom实例无效[系统] System.Runtime.InteropServices.DefaultParameterValueAttribute ::。ctor的(对象)=(01 00 08 02 00 00 00 00 00)
    ...
 

解决方案

C#编译器不使用[DefaultParameterValue]属性设置为默认值,它使用.PARAM指令来获得嵌入在元数据中的价值。仅仅记录在CLI规范顺便说一句,只有分区第二,章15.4.1提到,它可以有一个FieldInit值,15.4.1.4是沉默了。

这就是责无旁贷,在C ++ / CLI编译器不知道如何生成的指令。你不能让这项工作。

How can I declare a managed method in C++/CLI that has an optional parameter when used from C#?

I've decorated the parameter with both an Optional and a DefaultParameterValue attribute (see: How default parameter values are encoded), but only the Optional attribute seems to be honored.

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

Output:

0

Expected Output:

2

Visual C# IntelliSense:

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

Edit: A closer look with a disassembler reveals that the C++/CLI compiler does indeed not generate the required .param [1] = int32(2) directive. The IL code shown by Reflector is wrong.

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

解决方案

The C# compiler doesn't use the [DefaultParameterValue] attribute to set the default value, it uses the .param directive to get the value embedded in the metadata. Barely documented in the CLI spec btw, only Partition II, chapter 15.4.1 mentions that it can have a FieldInit value, 15.4.1.4 is silent about it.

That's where the buck stops, the C++/CLI compiler doesn't know how to generate the directive. You cannot make this work.