2009-04-03 8 views
10

Ich habe irgendwo auf MSDN gelesen, dass das Äquivalent zu Cis 'ist "Schlüsselwort wäre dynamic_cast, aber das ist nicht wirklich gleichwertig: Es funktioniert nicht mit Werttypen oder mit generischen Parametern. Zum Beispiel in C# kann ich schreiben:C++/CLI-Frage: Gibt es ein Äquivalent zum C# "is" -Schlüsselwort oder muss ich reflection verwenden?

void MyGenericFunction<T>() 
{ 
    object x = ... 
    if (x is T) 
     ...; 
} 

Wenn ich das "Äquivalent" C++/CLI versuchen:

generic<class T> 
void MyGenericFunction() 
{ 
    object x = ... 
    if (dynamic_cast<T>(x)) 
     ...; 
} 

ich einen Compiler-Fehler „Fehler C2682 erhalten: kann nicht 'dynamic_cast' verwenden, um von zu konvertieren 'System :: Object ^' bis 'T' ".

Das einzige, was ich denken kann, ist die Reflexion zu nutzen:

if (T::typeid->IsAssignableFrom(obj->GetType())) 

Gibt es einen einfacheren Weg, dies zu tun?

Antwort

6

Sie können safe_cast verwenden, wo Sie dynamic_cast in systemeigenem C++ verwenden und die System :: InvalidCastException auffangen. In Bezug auf kompatible Typen die Semantik der Frage, ob Sie Typen konvertieren können, könnte eine breitere Palette von Typen als die Identität überprüfen. Sie möchten möglicherweise die zusätzliche Flexibilität von IsAssignableFrom.

Ich glaube nicht, dass es ein effizientes Äquivalent zu dem guten alten dynamic_cast Idiom gibt, das wir gewohnt sind, sicherlich nichts so kompakt.

12

Es ist auf MSDN:

How to: Implement is and as C# Keywords in C++

Auf den Punkt gebracht, was Sie brauchen eine Hilfsfunktion zu schreiben, wie so:

template < class T, class U > 
Boolean isinst(U u) { 
    return dynamic_cast<T>(u) != nullptr; 
} 

und es so nennen:

Object^o = "f"; 
if (isinst< String^>(o)) 
    Console::WriteLine("o is a string"); 
+0

Vielleicht haben Sie meine Frage missverstanden. Ich kenne diesen MSDN-Artikel. Ich habe es in meiner Frage erwähnt. Und ich erklärte, warum es nicht für mich funktioniert. dynamic_cast entspricht nicht C# "as". Es funktioniert nur für Referenztypen. – Niki

+0

Ups, sollte Fragen genauer lesen. Es funktioniert für generische Typen, aber nicht für Werttypen. –

+9

C# ''as' funktioniert auch nicht für Werttypen:' dynamic_cast' ist das genaue Äquivalent von 'as'. Verwenden Sie 'safe_cast' zum Umwandeln in Werttypen. Die Semantik ist äquivalent zu der von C#: Wirf eine Exception für schlechte Casts, um Typen zu typisieren, gebe 'Null' für schlechte Casts zu Referenztypen zurück. –

1

Während eine einfache Abhilfe wäre, safe_cast<T>(x) zu verwenden undzu fangenhat dies den offensichtlichen Overhead der Ausnahmebehandlung (Abrollen des Stapels und des gesamten damit verbundenen Spaßes), wenn der Typ nicht übereinstimmt.

Ich versuchte, einen anderen Ansatz zu finden. Während ich es nicht genau einfach nennen würde, macht es seinen Job, ohne Ausnahmen zu verwenden.

#using <System.Core.dll> 

namespace detail 
{ 
    generic <typename T> ref class is_instance_of_managed_helper sealed abstract 
    { 
    public: 
     static initonly System::Func<System::Object^, bool>^ is_instance_of = build(); 

    private: 
     static System::Func<System::Object^, bool>^ build() 
     { 
      using System::Linq::Expressions::Expression; 
      auto param = Expression::Parameter(System::Object::typeid); 
      return Expression::Lambda<System::Func<System::Object^, bool>^>(
       Expression::TypeIs(param, T::typeid), 
       param)->Compile(); 
     } 
    }; 

    template <typename T> struct is_instance_of_helper 
    { 
     static bool is_instance_of(System::Object^ obj) 
     { 
      return is_instance_of_managed_helper<T>::is_instance_of(obj); 
     } 
    }; 

    template <typename T> struct is_instance_of_helper<T^> 
    { 
     static bool is_instance_of(System::Object^ obj) 
     { 
      return dynamic_cast<T^>(obj) != nullptr; 
     } 
    }; 
} 

template <typename T> bool is_instance_of(System::Object^ obj) 
{ 
    return detail::is_instance_of_helper<T>::is_instance_of(obj); 
} 

Ein wenig Erläuterung:

  • is_instance_of_managed_helper ist eine verwaltete Klasse, die eine Funktion zur Laufzeit geben das Äquivalent von C# 's is Operator erzeugt. Es verwendet Expression::TypeIs, um dies auf einfache Weise zu erreichen. Eine solche Funktion wird erzeugt einmal für jeden T.

  • template <typename T> struct is_instance_of_helper ist eine Template-Struktur, die einfach die obige Lösung verwendet. Dies ist der allgemeine Fall.

  • template <typename T> struct is_instance_of_helper<T^> ist eine teilweise Spezialisierung der obigen Struktur, die dynamic_cast für verwaltete Handle-Typen verwendet. Auf diese Weise ersparen wir uns die Mühe, Code zur Laufzeit zu erzeugen, wenn T einfach mit dynamic_cast verwendet werden kann.

  • template <typename T> bool is_instance_of(System::Object^ obj) ist die letzte Hilfsfunktion, die die zu verwendende Vorlage auswählt.

Verwandte Themen