C++/CLI: как использовать атрибут CallerMemberNameAttribute в C++/CLI?

В C# и VB.Net я могу использовать CallerMemberNameAttribute, чтобы получить имя вызывающего в виде строки:

public void Caller([CallerMemberName]string memberName = "")
{
   Debug.Print(memberName);
}

Я хотел бы сделать то же самое в C++/CLI, но почему-то я не могу заставить его работать. Пробовал несколько конструкций, и я начинаю задаваться вопросом, поддерживает ли компилятор C++/CLI этот атрибут.

Вот (упрощенная) реализация:

using namespace System::Runtime::CompilerServices;
public ref class InvokeExample
{
    Invoke([CallerMemberName][Optional]String^ name)
    {
        Debug::Print(name);
    }
}

При вызове этого метода в приложении C# значение name равно null. Также пытался с атрибутом DefaultParameterValue, но это тоже не помогло. Сейчас кончаются идеи.

Очевидный ответ будет: почему бы не реализовать в C#? Ну, в этом конкретном случае я ограничен C++/CLI.

1 ответ

Я использовал рефлектор для просмотра различий между C++/CLI и версией C#/VB.Net, и они выглядели абсолютно одинаково.

Тогда использовал ILDASM и теперь я думаю, что знаю, почему он не работает (после прочтения этого поста).

Вот код il:

C++/CLI

.method public hidebysig instance string 
        Caller([opt] string methodName) cil managed
{
  .param [1]
  .custom instance void [System]System.Runtime.InteropServices.DefaultParameterValueAttribute::.ctor(object) = ( 01 00 0E 00 00 00 ) 
  .custom instance void [mscorlib]System.Runtime.CompilerServices.CallerMemberNameAttribute::.ctor() = ( 01 00 00 00 ) 
  // Code size       2 (0x2)
  .maxstack  1
  IL_0000:  ldarg.1
  IL_0001:  ret
} // end of method ClassCPP::Caller

C#

.method public hidebysig instance string 
        Caller([opt] string methodName) cil managed
{
  .param [1] = ""
  .custom instance void [mscorlib]System.Runtime.CompilerServices.CallerMemberNameAttribute::.ctor() = ( 01 00 00 00 ) 
  // Code size       2 (0x2)
  .maxstack  1
  .locals init ([0] string CS$1$0000)
  IL_0000:  ldarg.1
  IL_0001:  ret
} // end of method ClassCS::Caller

IL-код из VB.Net отличается от C# следующим:

.param [1] = nullref

Я подозреваю, что поскольку C++/CLI испускает DefaultParameterValue вместо инициализации.param[1] значением по умолчанию, компилятор C# не будет преобразовывать это значение в имя члена вызывающей стороны.

Было бы удобно, если бы на страницах MSDN были описаны такие ограничения для проектов C++/CLI. Сэкономит нам много времени.

Другие вопросы по тегам