2009-04-03 12 views
10

Ho letto da qualche parte su MSDN che l'equivalente alla parola chiave "is" di C# sarebbe dynamic_cast, ma non è realmente equivalente: non funziona con i tipi di valore o con parametri generici. Per esempio in C# posso scrivere:C++/CLI-Domanda: Esiste un equivalente alla parola chiave C# "è" o devo usare la riflessione?

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

Se provo il "equivalente" C++/CLI:

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

ottengo un errore del compilatore "C2682 di errore: non può usare 'dynamic_cast' convertire da 'Sistema :: Oggetto ^' in 'T' ".

L'unica cosa che mi viene in mente è quello di utilizzare la riflessione:

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

C'è un modo più semplice per fare questo?

risposta

6

È possibile utilizzare safe_cast dove si utilizza dynamic_cast in C++ nativo e si intrappola System :: InvalidCastException. In termini di tipi compatibili , la semantica di chiedere se è possibile convertire i tipi potrebbe raccogliere una gamma più ampia di tipi rispetto alla verifica dell'identità. In realtà potresti volere la maggiore flessibilità di IsAssignableFrom.

Non penso che ci sia un equivalente efficiente del buon vecchio linguaggio dynamic_cast a cui siamo abituati, certamente niente di così compatto.

12

E 'su MSDN:

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

In poche parole, è necessario scrivere una funzione di supporto in questo modo:

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

e chiamare in questo modo:

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

Forse hai frainteso la mia domanda. So che l'articolo MSDN. L'ho menzionato nella mia domanda. E ho spiegato perché non funziona per me. dynamic_cast non è equivalente a C# "come". Funziona solo per i tipi di riferimento. – Niki

+0

Oops, dovrebbe leggere le domande più attentamente. Funziona per tipi generici, ma non per tipi di valore. –

+9

'' as' di C# non funziona per i tipi di valore: 'dynamic_cast' è l'equivalente esatto di' as'. Usa 'safe_cast' per eseguire il casting sui tipi di valore. Le semantiche sono equivalenti a quelle di C#: lancia un'eccezione per i cast errati ai tipi di valore, restituisce 'null' per i tipi di riferimento errati. –

1

Mentre una soluzione semplice sarebbe utilizzare safe_cast<T>(x) e catturare System::InvalidCastException^, questo ha l'ovvio overhead della gestione delle eccezioni (srotolare lo stack e tutto il divertimento correlato) quando il tipo non corrisponde.

Ho provato a proporre un approccio diverso. Mentre non lo chiamerei esattamente semplice, fa il suo lavoro senza usare eccezioni.

#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); 
} 

Un po 'di spiegazione:

  • is_instance_of_managed_helper è una classe gestita che genera una funzione in fase di esecuzione che dia un equivalente di is dell'operatore C#' s. Usa Expression::TypeIs per raggiungere questo in un modo semplice. Una tale funzione verrà generata una volta per ogni T.

  • template <typename T> struct is_instance_of_helper è una struttura di modello che utilizza semplicemente la soluzione di cui sopra. Questo è il caso generale.

  • template <typename T> struct is_instance_of_helper<T^> è una specializzazione parziale della struttura precedente che utilizza dynamic_cast per i tipi di handle gestiti. In questo modo, risparmieremo il problema di generare codice in fase di esecuzione quando T può essere semplicemente utilizzato con dynamic_cast.

  • template <typename T> bool is_instance_of(System::Object^ obj) è la funzione di supporto finale che sceglierà il modello da utilizzare.

Problemi correlati