2009-04-03 17 views
10

He leído en MSDN que el equivalente a la palabra clave "es" de C# sería dynamic_cast, pero eso no es realmente equivalente: no funciona con tipos de valores o con parámetros genéricos. Por ejemplo, en C# Puedo escribir:C++/CLI-Pregunta: ¿Hay un equivalente a la palabra clave "es" C o tengo que usar la reflexión?

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

Si intento el "equivalente" C++/CLI:

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

me sale un error del compilador C2682 de error": no se puede utilizar 'dynamic_cast' convertir de 'System :: Object ^' a 'T' ".

La única cosa que puedo pensar es utilizar la reflexión:

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

¿Existe una manera más sencilla de hacer esto?

Respuesta

6

Puede usar safe_cast donde usaría dynamic_cast en C++ nativo y atraparía System :: InvalidCastException. En términos de tipos compatibles la semántica de preguntar si puede convertir tipos podría recoger un rango más amplio de tipos que verificar la identidad. En realidad, es posible que desee la flexibilidad adicional de IsAssignableFrom.

No creo que haya un equivalente eficiente a la antigua y buena expresión dynamic_cast a la que estamos acostumbrados, sin duda nada compacta.

12

Es en MSDN:

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

En pocas palabras, tiene que escribir una función auxiliar, así:

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

y lo llaman así:

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

Quizás ha malentendido mi pregunta. Sé que ese artículo de MSDN. Lo mencioné en mi pregunta. Y expliqué por qué no funciona para mí. dynamic_cast no es equivalente a C# "as". Solo funciona para tipos de referencia. – Niki

+0

Vaya, debería leer las preguntas con más cuidado. Sí funciona para tipos genéricos, pero no para tipos de valores. –

+9

C# 's 'as' tampoco funciona para los tipos de valores:' dynamic_cast' es el equivalente exacto de 'as'. Use 'safe_cast' para convertir a tipos de valores. La semántica es equivalente a la de C#: lanza una excepción para los tipos erróneos para los tipos de valor, devuelve 'null' para los modelos erróneos a los tipos de referencia. –

1

Mientras que una solución simple sería usar safe_cast<T>(x) y atrapar System::InvalidCastException^, esto tiene la sobrecarga obvia del manejo de excepciones (desenrollar la pila y toda la diversión relacionada) cuando el tipo no coincide.

Traté de llegar a un enfoque diferente. Si bien no lo llamaría exactamente simple, hace su trabajo sin usar excepciones.

#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 poco de explicación:

  • is_instance_of_managed_helper es una clase administrada que genera una función en tiempo de ejecución dando el equivalente de is operador de C# 's. Utiliza Expression::TypeIs para lograr esto de una manera sencilla. Una de esas funciones se generará una vez por cada T.

  • template <typename T> struct is_instance_of_helper es una estructura de plantilla que simplemente utiliza la solución anterior. Este es el caso general.

  • template <typename T> struct is_instance_of_helper<T^> es una especialización parcial de la estructura anterior que usa dynamic_cast para los tipos de identificador gestionados. De esta forma, nos ahorraremos el problema de generar código en tiempo de ejecución cuando T se puede usar simplemente con dynamic_cast.

  • template <typename T> bool is_instance_of(System::Object^ obj) es la función auxiliar final que elegirá la plantilla para usar.

Cuestiones relacionadas