2012-01-19 28 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) का उपयोग करने का प्रयास किया .सविरिएंट। यह अभिन्न प्रकार के लिए काम किया, लेकिन बूलियन के लिए उड़ा दिया। मुझे काफी नहीं लगता है, क्योंकि आम तौर पर मैं एक संस्करण में एक बूलियन मान असाइन करने में सक्षम होता हूं ...

क्या यह रूपांतरण करने का कोई बेहतर तरीका है? मुझे केवल सरल अंतर्निर्मित प्रकारों (गणनाओं और अभिलेखों को छोड़कर) के लिए काम करने की आवश्यकता है

+0

आप प्रकार की एक स्थानीय चर बनाने की कोशिश की है 'संस्करण', इसे 'कुछ वैल्यू' असाइन करें, और उसके बाद स्थानीय चर को 'FMyIntf.DoStuff()' पर पास करें? –

+0

हां। मैं ऐसा नहीं कर सकता क्योंकि 'टी' से 'वेरिएंट' तक कोई वैध कलाकार नहीं है ... –

उत्तर

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 प्रकार रूपांतरण आंतरिक रूप से ज्यादातर संभालती है, इस समारोह को सरल बनाया जा सकता है। मैं मामले में enumerations संभाल लेंगे आप उन्हें बाद में की जरूरत सकता है:

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 टीवीएयू के आंतरिक में कुछ पोकिंग करने के बाद, यह पता चला है कि टाइपकिंड ऑफ बूलियन टीकेएनीमेशन है, और टीवीएयू एक प्रकार पर अपवाद उठाता है जब टाइपविंड टीकेइनेरेशन वाले मान पर एस्विरिएंट को कॉल किया जाता है। जिसका अर्थ है कि आपका उदाहरण - हालांकि यह अपवाद नहीं उठाता है - फिर भी गलत संस्करण लौटाता है, क्योंकि मेरा बूलियन 'असाधारण' रूपांतरित हो जाता है, जिसके परिणामस्वरूप अभिन्न प्रकार का एक संस्करण होता है - बूलियन नहीं ... शायद मुझे दोनों को जांचना होगा टाइपकिंड और टाइपनाम ... –

+0

@ माथीस फाल्कनबर्ग मैंने बूलियन को सही तरीके से संभालने के लिए अपना जवाब संपादित किया है। – Linas

+0

+1। आप रूपांतरण के समान महसूस करने के रूप में कई प्रकारों को परिवर्तित करके एक इष्टतम जेनेरिक टॉविरिएंट बना सकते हैं, कुछ प्रतिनिधित्व में जो एक संस्करण हो सकता है। यदि आप चाहते थे, तो आप नई TObject.ToString विधि का उपयोग करके महत्वपूर्ण स्थानीय वर्ग (TObject) प्रकारों को परिवर्तित करने के लिए कोड जोड़ सकते हैं। –

0

एक और तरीका है (XE10 परीक्षण किया)

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