2011-10-25 9 views
6

Ecco un frammento che mostra quello che sto cercando di realizzare:Conversione del valore di tipo <T> in Variant, è possibile?

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; 

So che al di sopra suddetto approccio con typecast è ingenuo, ma spero che si ottiene l'idea. Vorrei sostituirlo con un meccanismo di conversione.

TMyObject sarà sempre di tipo semplice come Integer, String, Single, Double.

Lo scopo di tale conversione è che la funzione VarType mi dà costante integer per ogni tipo semplice che posso memorizzare altrove.

Mi piacerebbe sapere se tale conversione è possibile?

Grazie per il vostro tempo.

risposta

6

È possibile utilizzare l'RTTI per ottenere queste informazioni, basta controllare il valore della proprietà TTypeInfo.Kind:

controllare questo codice di esempio

{$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. 

questo tornerà

Integer 
UnicodeString 
1

Non riesco a vedere come sia possibile farlo con i generici. Il compilatore deve sapere che un'istanza di tipo può essere assegnata a un Variant per qualsiasi possibile T. Non c'è modo per te di dire che il compilatore è possibile.

Se questo fosse un modello come in C++, sarebbe banale.

+0

+1, ho a lungo per i modelli C++ a Delfi ... –

+0

@seth Non sapevo che fossi un utente delphi.Ti sono sempre stato un tipo di parentesi graffa! –

+1

Di solito ma non esclusivamente. Uso Delphi come versione di C# in esecuzione eseguibile nativo (non sopporto essere in grado di utilizzare l'assemblaggio online) e mi piace molto –

1

Grazie ragazzi per le tue risposte:

Come @RRUZ hanno dimostrato che è possibile le (intendo non un severo controllo ma estraendo il tipo di dati). Stavo lavorando da solo in attesa di una risposta e ho trovato una soluzione più generica.

Così sto postulando qui:

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; 

Ancora una volta grazie!

+1

Non è necessario passare Valore, è possibile leggerlo direttamente da T. –

+0

C'è qualche indicazione che 'varType' contiene un valore valido quando' TypeInfo (T). Kind' is non 'tkDynArray'? O che il numero intero memorizzato in 'varType' è in realtà un valore' TVarType', dal momento che gli array dinamici possono contenere cose che 'Variant' non possono? Non penso che siano necessariamente veri. –

+0

@RobKennedy Ho paura che tu abbia ragione. Non capisco perché non funziona come previsto.Questo è un peccato ... – Wodzu

7

E 'banalmente risolvibile in Delphis con RTTI avanzato (2010 e successivi). Peccato che si è limitato al 2009 :(

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

Questo funziona solo per i tipi semplici, ma che era un vincolo specificato nella domanda.

+0

Grazie a @gabr sarà sicuramente utile quando passo a D2010 :) – Wodzu