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. Сэкономит нам много времени.