2012-01-19 110 views
11

我有一個公開的函數,以與一般類型的參數德爾福泛型類。在這個函數內部,我需要將一個泛型類型的實例傳遞給期望變體類型的另一個對象。類似於:如何從通用轉換爲變體,德爾福

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

你有沒有嘗試創建類型的局部變量'Variant',將'SomeValue'賦值給它,然後將局部變量傳遞給'FMyIntf.DoStuff()'? –

+0

是的。我不能這樣做,因爲從「T」到「變」 ... –

回答

10

我覺得這是對通用類型轉換爲變種,因爲變種不能容納所有可能的類型沒有直接的方法。您必須編寫具體的轉換例程。例如爲:

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處理大多數內部類型的轉換,該功能可被簡化。我會處理的情況下,枚舉,你可以在以後需要他們:

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; 

可能的用法:

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

我害怕它會是類似的東西:-P 有點戳關於TValue的內部後沒有有效的投,事實證明,布爾的TypeKind是tkEnumeration,當調用具有TypeKind tkEnumeration的值的AsVariant時,TValue引發異常。這也意味着你的例子 - 雖然它不會引發異常 - 仍然返回錯誤的Variant,因爲我的布爾被轉換爲'AsOrdinal',導致整型變體 - 不是布爾值...也許我需要檢查typekind和typename .... –

+0

@MathiasFalkenberg我編輯了我的答案來正確處理布爾值。 – Linas

+0

+1。您可以通過將您想要轉換的許多類型轉換爲可以作爲變體的某種表示形式來製作最佳的GenericToVariant。如果你想,你可以添加代碼來轉換重要的本地類(TObject)類型,使用新的TObject.ToString方法。 –

0

另一種方式(測試XE10)

Var 
    old : variant; 
    val : TValue; 
Begin 
    val := TValue.FromVariant(old); 
End;