2016-02-20 32 views
2

我正在使用Delphi Seattle Update1 Win64並嘗試使用RTTI提取屬性。我的目標是將組件屬性序列化爲JSON,因爲我需要在非Delphi環境中使用此信息。GetPropList與TRectangle返回StrokeThickness作爲屬性應該是Stroke類的一部分

我的問題是關於GetPropListTRectangle(例子),以及爲什麼它返回則不能傳遞到GetPropValue,即性質:

  1. StrokeThickness類型tkFloat
  2. StrokeCap類型tkEnumeration
  3. StrokeDash作爲類型tkEnumeration
  4. StrokeJoin as type tkEnum關合作。

GetPropList不正確地爲tkClass類型,這是我本來期望,並返回Stroke解析時,Stroke類回報ThicknessCapDashJoin,我可以得到這些正確的價值觀。

問題是執行GetPropValueStrokeThickness會導致異常。因此,我必須特別注意GetPropList返回的「破損」屬性,我想避免這種情況。

起初我還以爲這是與GetPropList返回屬性的問題根本不存在,但我可以執行以下代碼,他們都工作:

Rectangle1.StrokeThickness := 5; //works 

    Rectangle1.Stroke.Thickness := 10; //and also works 

型tkFloat或tkEnumeration工作的其他屬性預計並返回正確的值。

我創建了一個小測試應用程序來嘗試調試這個。我發現在StrokeThickness的情況下,M.Code在函數System.TypeInfo.TPropSet.GetProp(行2397)中爲零,我想解釋爲什麼會導致異常。

附加的是我創建的測試代碼,用於確認我在更大的項目中看到的內容。我將如何處理上面列出的四個屬性而無需特殊情況。

形式:

object Form1: TForm1 
    Left = 0 
    Top = 0 
    Caption = 'Form1' 
    ClientHeight = 202 
    ClientWidth = 542 
    FormFactor.Width = 320 
    FormFactor.Height = 480 
    FormFactor.Devices = [Desktop] 
    DesignerMasterStyle = 0 
    object Rectangle1: TRectangle 
    Position.X = 40.000000000000000000 
    Position.Y = 40.000000000000000000 
    Size.Width = 97.000000000000000000 
    Size.Height = 97.000000000000000000 
    Size.PlatformDefault = False 
    end 
    object StrokeThickness: TButton 
    Position.X = 40.000000000000000000 
    Position.Y = 144.000000000000000000 
    Size.Width = 97.000000000000000000 
    Size.Height = 22.000000000000000000 
    Size.PlatformDefault = False 
    TabOrder = 1 
    Text = 'RTTI' 
    OnClick = StrokeThicknessClick 
    end 
    object Memo1: TMemo 
    Touch.InteractiveGestures = [Pan, LongTap, DoubleTap] 
    DataDetectorTypes = [] 
    Position.X = 152.000000000000000000 
    Position.Y = 40.000000000000000000 
    Size.Width = 353.000000000000000000 
    Size.Height = 129.000000000000000000 
    Size.PlatformDefault = False 
    TabOrder = 2 
    Viewport.Width = 349.000000000000000000 
    Viewport.Height = 125.000000000000000000 
    end 
end 

測試代碼:

unit Unit1; 

interface 

uses 
    System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, 
    FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.StdCtrls, 
    FMX.Controls.Presentation, FMX.Edit, FMX.Objects, FMX.ScrollBox, FMX.Memo; 

type 
    TForm1 = class(TForm) 
    Rectangle1: TRectangle; 
    StrokeThickness: TButton; 
    Memo1: TMemo; 
    procedure StrokeThicknessClick(Sender: TObject); 
    private 
    { Private declarations } 
    public 
    { Public declarations } 
    end; 

var 
    Form1: TForm1; 

implementation 

uses System.TypInfo; 

{$R *.fmx} 

procedure TForm1.StrokeThicknessClick(Sender: TObject); 
var 
    vValue : String; 
    PropList : PPropList; 
    PropInfo : PPropInfo; 
    PropType : PPTypeInfo; 
    PropListCount : Integer; 
    I: Integer; 
begin 
    memo1.Lines.Clear; 

    PropListCount := GetPropList(Rectangle1, PropList); 

    for I := 0 to PropListCount-1 do 
    begin 
    PropInfo := PropList^[I]; 
    PropType := PropInfo^.PropType; 

    Memo1.Lines.Add('Name: '+String(PropInfo^.Name)); 
    Memo1.Lines.Add('PropType: '+String(PropInfo^.PropType^.Name)); 
    Memo1.Lines.Add('PropKind: '+GetEnumName(TypeInfo(TTypeKind), Ord(PropType^.Kind))); 
    Memo1.Lines.Add(''); 
    end; 

    vValue := GetPropValue(Rectangle1, 'Name');    //test string 
    Memo1.Lines.Add('Proprty Name = '+VarToStr(vValue)); 

    vValue := GetPropValue(Rectangle1, 'Height');    //test float 
    Memo1.Lines.Add('Property Height = '+VarToStr(vValue)); 

    vValue := GetPropValue(Rectangle1, 'Sides');    //test enumeration 
    Memo1.Lines.Add('Property Sides = '+VarToStr(vValue)); 

    //The following would cause an exception 
    { 
    vValue := GetPropValue(Rectangle1, 'StrokeThickness'); 
    Memo1.Lines.Add('Property StrokeThickness ='+VarToStr(vValue)); 
    } 

    Rectangle1.StrokeThickness := 5; //works ?? 

    //Still fails after it was explicitly set 
    { 
    vValue := GetPropValue(Rectangle1, 'StrokeThickness'); 
    Memo1.Lines.Add('Property StrokeThickness ='+VarToStr(vValue)); 
    } 

    Rectangle1.Stroke.Thickness := 10; //and also works... as expected 

    //The following with cause an exception 
    { 
    vValue := GetPropValue(Rectangle1, 'StrokeDash'); 
    Memo1.Lines.Add('StrokeDash = '+VarToStr(vValue)); 
    } 

end; 

end. 
+0

文件的錯誤報告用[QualityPortal](HTTP://quality.embarcadero .com),然後嘗試從'System.Rtti'單元切換到新樣式的RTTI,而不是使用'System.TypInfo'單元中的舊式RTTI,看看它是否在同一個屬性上崩潰。 –

+0

@RemyLebeau謝謝;會做。很高興在我提交錯誤之前得到確認我沒有做錯某些形式更好的人。我將用'System.Rtti'進行分叉和測試,但是我讀到它膨脹了代碼大小,所以我用'System.TypInfo'代替。我會比較一下,看看是否有任何影響。 – lowrider

+0

我不確認或否認這是否是一個錯誤,因爲我還沒有機會自己嘗試。但它聽起來像一個錯誤,報告它並沒有什麼壞處,你可以隨時關閉它。 –

回答

1

使用代碼等

var 
    LProperty: TRttiProperty; 
    LType: TRttiType; 
    LContext: TRttiContext; 
    LArray: TArray<TRttiProperty>; 
begin 
    LContext := TRTTIContext.Create; 
    LType := LContext.GetType(TRectangle); 
    LArray := LType.GetDeclaredProperties; 
    for LProperty in LArray do 
    begin 
    Memo1.Lines.Add('Name: ' + LProperty.Name); 
    Memo1.Lines.Add('PropType: ' + LProperty.PropertyType.Name); 
    Memo1.Lines.Add('PropKind: ' + GetEnumName(TypeInfo(TTypeKind), Ord(LProperty.PropertyType.TypeKind))); 
    if LProperty.IsReadable then 
    begin 
     Memo1.Lines.Add('Value: ' + LProperty.GetValue(Rectangle1).ToString); 
    end 
    else 
    begin 
     Memo1.Lines.Add('Value of the property cannot be read'); 
    end; 
    Memo1.Lines.Add(''); 
    end; 
end; 
+0

你能否給你的答案添加一些解釋? –

+0

對不起,我太矮了。因此,作者問題的原因是,屬性StrokeThickness,StrokeCap,StrokeDash和StrokeJoin是隻寫的。這就是爲什麼在嘗試讀取它們的值時發生異常。所以,解決方案是檢查屬性是否可讀或不可以。目前我不知道如何使用PPTypeInfo來做到這一點 - 我看到沒有合適的信息。在我自己的項目中的類似情況下,我使用System.Rtti單元和TRttiProperty,它提供了必需的檢查LProperty.IsReadable – Vitkus

相關問題