Необязательные параметры в управляемых методах C ++ / CLI - PullRequest
28 голосов
/ 12 февраля 2011

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

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


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 неверен.

Отражатель:

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

Ответы [ 3 ]

28 голосов
/ 12 февраля 2011

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

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

9 голосов
/ 27 сентября 2014

Есть способ заставить это работать (обходной путь).Волшебное слово имеет значение NULL, поскольку для типов NULL по умолчанию всегда используется значение «NULL» (.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());
5 голосов
/ 12 февраля 2011

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

...