How to get property name as string in managed C ++

I see a lot of entries for this in C #, but nothing for C ++

I have a set of properties in some managed C ++ code that is used to transfer data between the C # part and the C ++ part. On the C # side, the answer presented here works very well, and I would like to do something similar with C ++. Copy of the solution contained in Link:

string NameOf<T>(Expression<Func<T>> expr) { return ((MemberExpression) expr.Body).Member.Name; } var gmtList = new SelectList(repository.GetSystemTimeZones(), NameOf(() => tz.Id), NameOf(() => tz.DisplayName)); 

My problem is that I cannot get the correct syntax for the call, in particular this section:

 () => tz.DisplayName 

I can’t find a resource on the Internet that talks about how I will do this in C ++, so if anyone has any experience or links, I would really appreciate any help.

+6
source share
2 answers

I struggled with all these lambdas and cool System :: Linq spaces (including the CLinq library and other things) for several hours, and then ... I just thought: why not use a purely static solution?

We just announce

 /// Convert X to "X", the classical preprocessing trick #define GetPropName(TheClassName, ThePropertyName) #ThePropertyName 

and then we can do

 Console::WriteLine( GetPropName(TimeZone, Id) ); 

to get the "Id" printed on the screen.

Yes ... Now the interesting part. Type of security. I hear the storm of comment coming to this decision ("NO! It's not good, it does not check if ThePropertyName is in the class!")

OK Solution: create meaningless code using a macro that uses the value ThePropertyName in a dummy instance of TheClassName.

 /// This macro will produce the compilation error if ThePropertyName is not in the class named TheClassName #define CheckForPropertyExistence(TheClassName, ThePropertyName) \ /* Create an array of Objects which will be converted to string and ignored*/ \ (gcnew array<System::Object^> { (gcnew TheClassName())->ThePropertyName })->ToString() /// We get the property name using the "dinosaur strategy" - good old macro concatenated with the empty string which in turn is formed in CheckFor() macro #define GetPropertyName(TheClassName, ThePropertyName) \ (gcnew System::String(#ThePropertyName)) + CheckForPropertyExistence(TheClassName, ThePropertyName)->Substring(0,0) 

Now we can give a complete sample:

 using namespace System; /// Sample class public ref class TheTimeZone { public: TheTimeZone() { _Id = 0; _DisplayName = "tmp"; } property int Id { public: int get() {return _Id;} void set(int v) { _Id = v; } } property String^ DisplayName { public: String^ get() { return _DisplayName; } void set(String^ v) { _DisplayName = v; } } private: int _Id; String^ _DisplayName; }; /// This macro will produce the error if ThePropertyName is not in the class named TheClassName #define CheckForPropertyExistence(TheClassName, ThePropertyName) \ /* Create an array of Objects which will be converted to string and ignored*/ \ (gcnew array<System::Object^> { (gcnew TheClassName())->ThePropertyName })->ToString() /// We get the property name using the "dinosaur strategy": /// good old macro concatenated with the empty string /// which in turn is formed in CheckFor() macro #define GetPropertyName(TheClassName, ThePropertyName) \ (gcnew System::String(#ThePropertyName)) + \ CheckForPropertyExistence(TheClassName, ThePropertyName)->Substring(0,0) /// To get properties from objects with no default constructor #define GetPropertyNameForObject(TheObject, ThePropertyName) \ (gcnew System::String(#ThePropertyName)) + \ (gcnew array<System::Object^> { (TheObject)-> ThePropertyName })->ToString()->Substring(0,0) /// Test for our macros int main(array<System::String ^> ^args) { /// Prints "Length" /// We cannot use default constructor here Console::WriteLine(GetPropertyNameForObject (gcnew System::String("test"), Length) ); /// Prints "Id" Console::WriteLine(GetPropertyName (TheTimeZone, Id) ); /// Uncomment and get the error //Console::WriteLine(GetPropertyName (TheTimeZone, Id23) ); return 0; } 
+6
source

Lambda expressions in C # are syntactic sugar for delegates, so you will need to find the delegate equivalent of lambda expressions in order to have the same functionality in C ++ / CLI.

To make your life a little easier, you can explore CLinq (see the section “Lambda Expressions”), which provides the C ++ / CLI Wrapper for Linq

Note. Do not confuse C ++ 11 lambda expressions with C # lambda expressions. The first is only supported for native code. You can use lambdas C ++ 11, but you need to do extra work to provide them with delegates ( this CodeProject article explores the condition)

+2
source

Source: https://habr.com/ru/post/915270/


All Articles