2009-05-29 11 views
7

मैं एक लौटा आधार वस्तु को अपने विशिष्ट जेनेरिक प्रकार में डालने की कोशिश कर रहा हूं। नीचे दिया गया कोड मुझे लगता है कि काम करना चाहिए लेकिन एक आंतरिक संकलक त्रुटि उत्पन्न करता है, क्या ऐसा करने का कोई और तरीका है?मैं ऑब्जेक्ट को जेनेरिक में कैसे डाल सकता हूं?

type 
    TPersistGeneric<T> = class 
    private 
    type 
    TPointer = ^T; 
    public 
    class function Init : T; 
    end; 

class function TPersistGeneric<T>.Init : T; 
var 
    o : TXPersistent; // root class 
begin 
    case PTypeInfo(TypeInfo(T))^.Kind of 
    tkClass : begin 
       // xpcreate returns txpersistent, a root class of T 
       o := XPCreate(GetTypeName(TypeInfo(T))); // has a listed of registered classes 
       result := TPointer(pointer(@o))^; 
       end; 
    else 
     result := Default(T); 
    end; 
end; 

उत्तर

14

मैं टाइपकास्ट हेल्पर क्लास का उपयोग कर रहा हूं जो टाइपकास्ट करता है और यह भी जांचता है कि क्या दो वर्ग संगत हैं।

type 
    TTypeCast = class 
    public 
    // ReinterpretCast does a hard type cast 
    class function ReinterpretCast<ReturnT>(const Value): ReturnT; 
    // StaticCast does a hard type cast but requires an input type 
    class function StaticCast<T, ReturnT>(const Value: T): ReturnT; 
    // DynamicCast is like the as-operator. It checks if the object can be typecasted 
    class function DynamicCast<T, ReturnT>(const Value: T): ReturnT; 
    end; 

class function TTypeCast.ReinterpretCast<ReturnT>(const Value): ReturnT; 
begin 
    Result := ReturnT(Value); 
end; 

class function TTypeCast.StaticCast<T, ReturnT>(const Value: T): ReturnT; 
begin 
    Result := ReinterpretCast<ReturnT>(Value); 
end; 

class function TTypeCast.DynamicCast<T, ReturnT>(const Value: T): ReturnT; 
var 
    TypeT, TypeReturnT: PTypeInfo; 
    Obj: TObject; 
    LClass: TClass; 
    ClassNameReturnT, ClassNameT: string; 
    FoundReturnT, FoundT: Boolean; 
begin 
    TypeT := TypeInfo(T); 
    TypeReturnT := TypeInfo(ReturnT); 
    if (TypeT = nil) or (TypeReturnT = nil) then 
    raise Exception.Create('Missing Typeinformation'); 
    if TypeT.Kind <> tkClass then 
    raise Exception.Create('Source type is not a class'); 
    if TypeReturnT.Kind <> tkClass then 
    raise Exception.Create('Destination type is not a class'); 

    Obj := TObject(Pointer(@Value)^); 
    if Obj = nil then 
    Result := Default(ReturnT) 
    else 
    begin 
    ClassNameReturnT := UTF8ToString(TypeReturnT.Name); 
    ClassNameT := UTF8ToString(TypeT.Name); 
    LClass := Obj.ClassType; 
    FoundReturnT := False; 
    FoundT := False; 
    while (LClass <> nil) and not (FoundT and FoundReturnT) do 
    begin 
     if not FoundReturnT and (LClass.ClassName = ClassNameReturnT) then 
     FoundReturnT := True; 
     if not FoundT and (LClass.ClassName = ClassNameT) then 
     FoundT := True; 
     LClass := LClass.ClassParent; 
    end; 
    //if LClass <> nil then << TObject doesn't work with this line 
    if FoundT and FoundReturnT then 
     Result := ReinterpretCast<ReturnT>(Obj) 
    else 
    if not FoundReturnT then 
     raise Exception.CreateFmt('Cannot cast class %s to %s', 
           [Obj.ClassName, ClassNameReturnT]) 
    else 
     raise Exception.CreateFmt('Object (%s) is not of class %s', 
           [Obj.ClassName, ClassNameT]); 
    end; 
end; 
+1

बहुत बुरा मैं इसे पसंदीदा उत्तर के रूप में चिह्नित नहीं कर सकता ... – gabr

+0

यह अधिक है! – kabstergo

1

एंड्रियास से जवाब ऊपर शानदार है:

class function TPersistGeneric<T>.Init: T; 
var 
    o : TXPersistent; // root class 
begin 
    case PTypeInfo(TypeInfo(T))^.Kind of 
    tkClass : begin 
       // xpcreate returns txpersistent, a root class of T 
       o := XPCreate(GetTypeName(TypeInfo(T))); // has a listed of registered classes 
       Result := TTypeCast.DynamicCast<TXPersistent, T>(o); 
       end; 
    else 
     result := Default(T); 
    end; 

यहाँ वर्ग है। यह वास्तव में डेल्फी में जेनेरिक के उपयोग में मेरी मदद करता है। कृपया मुझे एंड्रियास को क्षमा करें क्योंकि मुझे आश्चर्य है कि डायनामिककास्ट थोड़ा जटिल है या नहीं। अगर मैं गलत हूं तो कृपया मुझे सही करें, लेकिन निम्नलिखित थोड़ा संक्षिप्त, सुरक्षित, तेज़ (कोई स्ट्रिंग तुलना नहीं) होना चाहिए और अभी भी कार्यात्मक होना चाहिए।

वास्तव में मैंने जो कुछ किया है, वह गतिशील कैस्ट प्रकार पैरा पर क्लास बाधा का उपयोग करता है ताकि संकलक को कुछ काम करने की अनुमति मिल सके (जैसे मूल हमेशा गैर-वर्ग पैरामीटर को छोड़कर) और फिर TObject.InheritsFrom का उपयोग करें प्रकार संगतता की जांच करने के लिए समारोह।

मैं भी एक TryCast समारोह काफी उपयोगी करने के विचार मिल गया है (यह मेरे लिए एक आम कार्य है वैसे भी!)

इस कोर्स की है, जब तक मैं मिलान के लिए वर्ग के माता पिता trawling में कहीं बिंदु नहीं छूटा है नाम ... जो आईएमएचओ थोड़ा खतरनाक है, क्योंकि टाइप नाम अलग-अलग क्षेत्रों में गैर संगत कक्षाओं के लिए मेल खाते हैं।

वैसे भी, मेरा कोड है (डेल्फी XE3 के लिए काम करता है ... TryCast के D2009 संगत संस्करण के बाद निम्नानुसार है)।

type 
    TTypeCast = class 
    public 
    // ReinterpretCast does a hard type cast 
    class function ReinterpretCast<ReturnT>(const Value): ReturnT; 
    // StaticCast does a hard type cast but requires an input type 
    class function StaticCast<T, ReturnT>(const Value: T): ReturnT; 
    // Attempt a dynamic cast, returning True if successful 
    class function TryCast<T, ReturnT: class>(const Value: T; out Return: ReturnT): Boolean; 
    // DynamicCast is like the as-operator. It checks if the object can be typecasted 
    class function DynamicCast<T, ReturnT: class>(const Value: T): ReturnT; 
    end; 

implementation 

uses 
    System.SysUtils; 


class function TTypeCast.ReinterpretCast<ReturnT>(const Value): ReturnT; 
begin 
    Result := ReturnT(Value); 
end; 

class function TTypeCast.StaticCast<T, ReturnT>(const Value: T): ReturnT; 
begin 
    Result := ReinterpretCast<ReturnT>(Value); 
end; 

class function TTypeCast.TryCast<T, ReturnT>(const Value: T; out Return: ReturnT): Boolean; 
begin 
    Result := (not Assigned(Value)) or Value.InheritsFrom(ReturnT); 
    if Result then 
    Return := ReinterpretCast<ReturnT>(Value); 
end; 

class function TTypeCast.DynamicCast<T, ReturnT>(const Value: T): ReturnT; 
begin 
    if not TryCast<T, ReturnT>(Value, Result) then 
    //Value will definately be assigned is TryCast returns false 
    raise EInvalidCast.CreateFmt('Invalid class typecast from %s(%s) to %s', 
     [T.ClassName, Value.ClassName, ReturnT.ClassName]); 
end; 

जैसा कि डी 200 9 संस्करण का वादा किया गया था (रिटर्नटी के वर्ग में जाने के लिए कुछ छोटे प्रयासों की आवश्यकता है)।

class function TTypeCast.TryCast<T, ReturnT>(const Value: T; out Return: ReturnT): Boolean; 
var 
    LReturnTypeInfo: PTypeInfo; 
    LReturnClass: TClass; 
begin 
    Result := True; 
    if not Assigned(Value) then 
    Return := Default(ReturnT) 
    else 
    begin 
    LReturnTypeInfo := TypeInfo(ReturnT); 
    LReturnClass := GetTypeData(LReturnTypeInfo).ClassType; 
    if Value.InheritsFrom(LReturnClass) then 
     Return := ReinterpretCast<ReturnT>(Value) 
    else 
     Result := False; 
    end; 
end; 
संबंधित मुद्दे