2011-08-24 11 views
5

प्रश्न में here SetValue के साथ उपयोग करने के लिए एक संगत टीवील्यू बनाने के लिए एक विधि दिखाया गया है। मैं एक आईएनआई फ़ाइल में कक्षा को स्टोर करने के लिए आरटीटीआई का उपयोग करने के लिए इसका एक सामान्य संस्करण बनाने की कोशिश कर रहा हूं। यह मेरा कटौती कोड है:मैं गणना किए गए आरटीटीआई फ़ील्ड के लिए जेनेरिक टीवील्यू कैसे बना सकता हूं?

procedure TMyClass.LoadRTTI(xObject: TObject); 
var 
    LContext: TRttiContext; 
    LClass: TRttiInstanceType; 
    xField : TRttiField; 
    szNewValue : String; 
    xValue : TValue; 
begin 
    LContext := TRttiContext.Create; 
    LClass := LContext.GetType(xObject.ClassType) as TRttiInstanceType; 

    for xField in LClass.GetDeclaredFields do 
    begin 
    szNewValue := IniFile.ReadString(szSection, xField.Name, ''); 
    if szNewValue <> '' then // emumerated will be '0' (zero) as that is what GetValue.AsString returns 
    begin 
     case xField.FieldType.TypeKind of 
     tkEnumeration: xValue := StrToIntDef(szNewValue, xField.GetValue(xObject).AsOrdinal); 
     end; 
     xField.SetValue(xObject, xValue); // FAILS HERE with 'Invalid calss typecast 
    end; 
    end; 
end; 

जवाब संदर्भित में, समाधान TValue.From() पद्धति का उपयोग करके मूल्य मिल गया था, लेकिन वह उचित प्रकार का एक चर की आवश्यकता प्रतीत होता है। मेरे पास ऐसा कोई प्रकार नहीं है क्योंकि मेरे कोड को यह नहीं पता कि यह क्या है।

मैं आरटीटीआई से एक स्ट्रिंग में मूल्य प्राप्त करने के लिए एक सामान्य तरीके का उदाहरण ढूंढ रहा हूं, और इसे बाद में वापस रखूंगा। मुझे एक अच्छा ट्यूटोरियल नहीं मिला है जो अभी तक इसे कवर करता है।

procedure TMyClass.LoadRTTI(xObject: TObject); 
var 
    LContext: TRttiContext; 
    LClass: TRttiInstanceType; 
    xField : TRttiField; 
    szNewValue : String; 
    xValue : TValue; 
begin 
    LContext := TRttiContext.Create; 
    LClass := LContext.GetType(xObject.ClassType) as TRttiInstanceType; 

    for xField in LClass.GetDeclaredFields do 
    begin 
    szNewValue := IniFile.ReadString(szSection, xField.Name, ''); 
    if szNewValue <> '' then // emumerated will be '0' (zero) as that is what GetValue.AsString returns 
    begin 
     case xField.FieldType.TypeKind of 
     tkEnumeration: 
        begin 
        //get the instance to the TValue to set 
        xValue:=xField.GetValue(xObject); 
        //convert the data to a valid TValue 
        xValue:=TValue.FromOrdinal(xValue.TypeInfo,GetEnumValue(xValue.TypeInfo,szNewValue)); 
        end; 

     end; 
     //assign the new value from the TValue 
     xField.SetValue(xObject, xValue); 
    end; 
    end; 
end; 

उत्तर

7

आप एक मूल्य assing पहले सेट, और फिर enumerated मूल्य के लिए स्ट्रिंग में कनवर्ट GetEnumValue फ़ंक्शन का उपयोग करने के लिए

इस कोड का प्रयास करें TValue के लिए एक उदाहरण मिलता है चाहिए उदाहरण कोड यह दिखाता है कि यह कैसे करें:

var 
    V : TValue; 
    OrdValue : Integer; 
    C : TRttiContext; 
    F : TRttiField; 
    lTypeInfo : PTypeInfo; 
begin 

    // Pick a Enumerated Field 
    F := C.GetType(TForm).GetField('FFormStyle'); 

    // Get the TypeInfo for that field 
    lTypeInfo := F.FieldType.Handle; 

    // Setting TValue from an Enumeration Directly. 
    V := TValue.From(FormStyle); 
    ShowMessage(V.ToString); 
    // Setting TValue from the ordinal value of a Enumeration 
    OrdValue := ord(FormStyle); 
    V := TValue.FromOrdinal(lTypeInfo,OrdValue); 
    ShowMessage(V.ToString); 
    // Setting TValue from the String Value of an enumeration. 
    OrdValue := GetEnumValue(lTypeInfo,'fsStayOnTop'); 
    V := TValue.FromOrdinal(lTypeInfo,OrdValue); 
    ShowMessage(V.ToString); 
end; 
+0

ठीक है, यह मेरे काम कोड में चालाक होने के बाद ठीक से काम करता है। आईएनआई में सहेजने के लिए मूल्य प्राप्त करने के लिए, बस xField.GetValue (xObject) का उपयोग करें। ToString; – mj2008

6

यहाँ कुछ है:

+0

इसके लिए धन्यवाद - यह विकल्पों और विकल्पों का एक अच्छा सेट है जो प्रश्न को अन्य परिस्थितियों में ऐसा करने का बेहतर रिकॉर्ड देगा। – mj2008

0

मुझे एक ही समस्या थी, लेकिन मैंने इसे एक और तरीका हल किया। एक तेज़ तरीका:

type 
    CustType = (ctNone, ctEverything, ctNothing); 

    TObjctCust = class(TObject) 
    InfoType: CustType; 
    end; 

procedure TForm34.Button1Click(Sender: TObject); 
var 
    CurContext: TRttiContext; 
    Test: TObjctCust; 
    CurClassType: TRttiType; 
    CurFields: TArray<TRttiField>; 
    I: Integer; 
    Field: TRttiField; 
    TypeValue: Integer; 
    LFieldPointer: Pointer; 
    TypedSmallInt: SmallInt; 
begin 
    Test := TObjctCust.Create; 

    CurContext := TRttiContext.Create; 
    CurClassType := CurContext.GetType(Test.ClassType); 
    CurFields := CurClassType.GetFields; 

    //Here you can set any integer value you'd like to set in the type field. For example the result of query (AsInteger, AsOrdinal) 
    TypeValue := 1; 
    for I := 0 to Length(CurFields) -1 do 
    begin 
    Field := CurFields[I]; 
    if Field.FieldType.TypeKind = tkEnumeration then 
    begin 
     //Here is the solution, I change the value direct in the field position 
     LFieldPointer := Pointer(PByte(Test) + Field.Offset); 
     TypedSmallInt := TypeValue; 
     Move(TypedSmallInt, LFieldPointer^, Field.FieldType.TypeSize); 
    end; 
    end; 

    ShowMessage(IntToStr(Ord(Test.InfoType))); 
end; 
संबंधित मुद्दे