2011-10-25 3 views
6

Aquí hay un fragmento que muestra lo que estoy tratando de lograr:Convirtiendo el valor del tipo <T> en Variant, ¿es posible?

type 
    TMyObject<T> = class (TObject) 
    function GetVarType(Value: T): TVarType; 
    end; 


function TMyObject<T>.GetVarType(Value: T): TVarType; 
var 
    TmpValue: Variant; 
begin 
    TmpValue := Variant(Value); //Invalid typecast 
    Result := VarType(TmpValue); 
end; 

Sé que apporach anterior con encasillado es ingenuo, pero espero que se entiende la idea. Me gustaría reemplazarlo con algún mecanismo de conversión.

TMyObject siempre será de tipo simple como Integer, String, Single, Double.

El propósito de tal conversión es que la función VarType me da una constante entera para cada tipo simple que puedo almacenar en otro lugar.

Me gustaría saber si tal conversión es posible?

Gracias por su tiempo.

Respuesta

6

Puede utilizar el RTTI para obtener esta información, simplemente comprobar el valor de la propiedad TTypeInfo.Kind:

Comprobar este código de ejemplo

{$APPTYPE CONSOLE} 

uses 
    TypInfo, 
    Variants, 
    Generics.Collections, 
    SysUtils; 

type 
    TMyObject<T> = class (TObject) 
    function GetVarType(Value: T): TVarType; 
    end; 


function TMyObject<T>.GetVarType(Value: T): TVarType; 
begin 
    Case PTypeInfo(TypeInfo(T))^.Kind of 
    tkInteger : Result:=varInteger; 
    tkFloat : Result:=varDouble; 
    tkString : Result:=varString; 
    tkUString : Result:=varUString; 
    //add more types here 
    End; 
end; 

Var 
    LObj : TMyObject<Integer>; 
begin 
    try 
    Writeln(VarTypeAsText(TMyObject<Integer>.Create.GetVarType(5))); 
    Writeln(VarTypeAsText(TMyObject<String>.Create.GetVarType('Test'))); 
    except 
    on E: Exception do 
     Writeln(E.ClassName, ': ', E.Message); 
    end; 
    Readln; 
end. 

esto devolverá

Integer 
UnicodeString 
1

No veo cómo podría hacerse esto con genéricos. El compilador necesita saber que una instancia de tipo T se puede asignar a Variant para cualquier posible T. No hay forma de que le digas a ese compilador que es posible.

Si esto fuera plantillas como en C++, sería trivial.

+0

1, I de largo para las plantillas de C++ en Delphi ... –

+0

@seth No sabía que eras un usuario de delphi. ¡Siempre te tenía como un tipo de llaves! –

+1

Normalmente, pero no exclusivamente. Utilizo Delphi como una versión generadora de ejecutables nativos de C# (no puede soportar ser capaz de usar el ensamble en línea) y me gusta mucho. –

1

Gracias chicos para sus respuestas:

Como @RRUZ han demostrado que es possib le (me refiero a una asignación estricta pero no a extraer el tipo de datos). Estaba trabajando solo mientras esperaba una respuesta y encontré una solución más genérica.

así que estoy postulando aquí:

type 
    TMyObject<T> = class (TObject) 
    function GetVarType(Value: T): TVarType; 
    end; 


function TMyObject<T>.GetVarType(Value: T): TVarType; 
begin 
    Result := GetTypeData(TypeInfo(T)).varType; 
end; 

Una vez más, gracias!

+1

No es necesario pasar el valor, puede leerlo directamente desde T. –

+0

¿Hay alguna indicación de que 'varType' contenga un valor válido cuando' TypeInfo (T). Kind' es no 'tkDynArray'? ¿O que el entero almacenado en 'varType' es realmente un valor' TVarType', ya que las matrices dinámicas pueden contener cosas que 'Variant' no puede? No creo que ninguno sea necesariamente verdadero. –

+0

@RobKennedy Me temo que tienes razón. No entiendo por qué no está funcionando como se esperaba.Es una lástima ... – Wodzu

7

Es trivially Solucionable en Delphis con RTTI mejorado (2010 y más reciente). Lástima que está limitado a 2009 :(

function TMyObject<T>.GetVarType(Value: T): TVarType; 
begin 
    Result := VarType(TValue.From<T>(Value).AsVariant); 
end; 

Esto funciona sólo para los tipos simples, pero que era una restricción especificada en la pregunta.

+0

Gracias @gabr será definitivamente útil cuando cambie a D2010 :) – Wodzu

Cuestiones relacionadas