2012-01-19 9 views
11

Mam klasę generyczną Delphi, która udostępnia funkcję z argumentem typu ogólnego. Wewnątrz tej funkcji, muszę przekazać instancję typu ogólnego do innego obiektu oczekującego typu Wariant. Podobny do tego:Jak mogę przekonwertować z generic na Variant w Delphi

type 
    IMyInterface = interface 
    DoStuff(Value: Variant); 
    end;  

    TMyClass<T> = class 
    FMyIntf: IMyInterface 
    procedure DoStuff(SomeValue: T); 
    end; 

[...] 

procedure MyClass<T>.DoStuff(SomeValue: T); 
begin 
    FMyIntf.DoStuff((*convert SomeValue to Variant here*)); 
end; 

Próbowałem za pomocą Rtti.TValue.From (SomeValue) .AsVariant. To działało dla typów integralnych, ale wybuchło dla Booleans. Nie do końca rozumiem, dlaczego, ponieważ normalnie mógłbym przypisać wartość logiczną do wariantu ...

Czy istnieje lepszy sposób na dokonanie tej konwersji? Potrzebuję go tylko do pracy z prostymi wbudowanymi typami (z wyłączeniem wyliczeń i rekordów).

+0

Czy próbowałeś tworząc lokalną zmienną typu 'Variant', przypisz' SomeValue' do niego, a następnie przekaż lokalną zmienną do 'FMyIntf.DoStuff()'? –

+0

Tak. Nie mogę tego zrobić, ponieważ nie ma ważnej obsady od "T" do "Wariantu" ... –

Odpowiedz

10

Myślę, że nie ma bezpośredniej metody konwersji rodzaju generycznego na wariant, ponieważ wariant nie może zawierać wszystkich możliwych typów. Musisz napisać swoją konkretną procedurę konwersji. Np .:

interface 
//... 
type 
    TDemo = class 
    public 
    class function GetAsVariant<T>(const AValue: T): Variant; 
    end; 
//... 
implementation 
uses 
    Rtti, 
    TypInfo; 
//... 

{ TDemo} 

class function TDemo.GetAsVariant<T>(const AValue: T): Variant; 
var 
    val: TValue; 
    bRes: Boolean; 
begin 
    val := TValue.From<T>(AValue); 
    case val.Kind of 
    tkInteger: Result := val.AsInteger; 
    tkInt64: Result := val.AsInt64; 
    tkEnumeration: 
    begin 
     if val.TryAsType<Boolean>(bRes) then 
     Result := bRes 
     else 
     Result := val.AsOrdinal; 
    end; 
    tkFloat: Result := val.AsExtended; 
    tkString, tkChar, tkWChar, tkLString, tkWString, tkUString: 
     Result := val.AsString; 
    tkVariant: Result := val.AsVariant 
    else 
    begin 
     raise Exception.Create('Unsupported type'); 
    end; 
    end; 
end; 

Ponieważ TValue.AsVariant obsługuje większość konwersji typu wewnętrznie, funkcja ta może być uproszczona. będę obsługiwać wyliczeń w przypadku mogłyby trzeba je później:

class function TDemo.GetAsVariant<T>(const AValue: T): Variant; 
var 
    val: TValue; 
begin 
    val := TValue.From<T>(AValue); 
    case val.Kind of 
    tkEnumeration: 
    begin 
     if val.TypeInfo = TypeInfo(Boolean) then 
     Result := val.AsBoolean 
     else 
     Result := val.AsOrdinal; 
    end 
    else 
    begin 
     Result := val.AsVariant; 
    end; 
    end; 

Możliwe wykorzystanie:

var 
    vValue: Variant; 
begin 
    vValue := TDemo.GetAsVariant<Boolean>(True); 
    Assert(vValue = True); //now vValue is a correct Boolean 
+0

Obawiałem się, że to będzie coś takiego :-P Po krótkiej pogaduszce w wewnętrznych partiach TValue, okazuje się, że TypeKind obiektu typu Boolean to TK.numeration, a TValue podnosi wyjątek podczas wywoływania AsVariant na wartości mającej wartość Tokenumer TypeKind. Co oznacza również twój przykład - mimo że nie budzi wyjątku - nadal zwraca zły wariant, ponieważ moja wartość logiczna zostaje przekształcona w "AsOrdinal", co skutkuje wariantem typu integralnego - nie boolean ... Być może muszę sprawdzić zarówno typekind i nazwa pliku .... –

+0

@MathiasFalkenberg Edytowałem swoją odpowiedź, aby poprawnie obsługiwać bajtyans. – Linas

+0

+1. Możesz stworzyć optymalny GenericToVariant, konwertując tylu typów, ile chcesz, w konwersję, w reprezentację, która może być wariantem. Jeśli chcesz, możesz dodać kod do przekonwertowania ważnych lokalnych typów klas (TObject) przy użyciu nowej metody TObject.ToString. –

0

Innym sposobem (testowane XE10)

Var 
    old : variant; 
    val : TValue; 
Begin 
    val := TValue.FromVariant(old); 
End; 
Powiązane problemy