2012-01-19 7 views
11

ジェネリック型の引数を持つ関数を公開するDelphiジェネリッククラスがあります。この関数の中で、汎用型のインスタンスをVariant型を予期している別のオブジェクトに渡す必要があります。これと同様:デルファイでジェネリックからバリアントに変換するには

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; 

私はRtti.TValue.From(SomeValue).AsVariantを使ってみました。これは整数型では機能しましたが、ブーリアンでは爆発しました。私は、通常、なぜ私はバリアントにブール値を割り当てることができるだろうと思う理由はよく分かりません...

この変換を行う良い方法はありますか?

+0

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; 

可能な使用法:私はあなたが後でそれらを必要とすることができる場合の列挙を処理します'Variant'、' SomeValue'を代入し、ローカル変数を 'FMyIntf.DoStuff()'に渡しますか? –

+0

はい。 'T'から 'Variant'への有効なキャストがないので、私はそれを行うことができません... –

答えて

10

一般的な型をvariantに変換する直接的な方法はないと思います。変形はすべての可能な型を保持できないためです。特定の変換ルーチンを記述する必要があります。例えば:

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; 

TValue.AsVariantは、内部で型変換のほとんどを処理しているため、この機能を簡略化することができます。あなたがタイプのローカル変数を作成しようとしたことがあり

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

私はそれが何かのようになるのではないかと心配しました:-P TValueの内部で、 BooleanのTypeKindがtkEnumerationであり、TypeKind tkEnumerationを持つ値でAsVariantを呼び出すときにTValueが例外を送出することが判明しました。これは、例外が発生しないにもかかわらず、私のブール値が 'AsOrdinal'に変換され、Integer型のVariantとなるため、間違ったVariantを返すことを意味します。 typekindとtypename .... –

+0

@ MathiasFalkenberg私はブール値を正しく処理するために私の答えを編集しました。 – Linas

+0

+1。最適化されたGenericToVariantは、変換したいと思うほど多くの型をある種の表現に変換することで変種にすることができます。必要に応じて、新しいTObject.ToStringメソッドを使用して、重要なローカルクラス(TObject)型を変換するコードを追加できます。 –

0

別の方法(XE10をテストした)

Var 
    old : variant; 
    val : TValue; 
Begin 
    val := TValue.FromVariant(old); 
End; 
関連する問題