代码之家  ›  专栏  ›  技术社区  ›  Branko

作为函数结果的属性是否具有空属性值?

  •  2
  • Branko  · 技术社区  · 8 年前
    program Test;
    
    {$APPTYPE CONSOLE}
    
    uses
      System.SysUtils,
      System.Rtti;
    
    function GetPropertyValue(const AObject: TObject; APropertyName: string): TValue;
    var
      oType: TRttiType;
      oProp: TRttiProperty;
    begin
      oType := TRttiContext.Create.GetType(AObject.ClassType);
      if oType <> nil then
      begin
        oProp := oType.GetProperty(APropertyName);
        if oProp <> nil then
          Exit(oProp.GetValue(AObject));
      end;
      Result := TValue.Empty;
    end;
    
    function GetAttributePropertyValue(const AClass: TClass; AAttribute: TClass;
      AAttributePropertyName: string): TValue;
    var
      oAttr: TCustomAttribute;
    begin
      for oAttr in TRttiContext.Create.GetType(AClass).GetAttributes do
        if oAttr.InheritsFrom(AAttribute) then
          Exit(GetPropertyValue(oAttr, AAttributePropertyName));
      Result := nil;
    end;
    
    function GetClassAttribute(const AClass: TClass; AAttribute: TClass): TCustomAttribute;
    begin
      for Result in TRttiContext.Create.GetType(AClass).GetAttributes do
        if Result.InheritsFrom(AAttribute) then
          Exit;
      Result := nil;
    end;
    
    type
      DescriptionAttribute = class(TCustomAttribute)
      private
        FDescription: string;
      public
        constructor Create(const ADescription: string);
        property Description: string read FDescription;
      end;
    
    constructor DescriptionAttribute.Create(const ADescription: string);
    begin
      FDescription := ADescription;
    end;
    
    type
      [Description('MyClass description')]
      TMyClass = class(TObject);
    
    var
      oAttr: TCustomAttribute;
    begin
      { ok, output is 'MyClass description' }
      WriteLn(GetAttributePropertyValue(TMyClass, DescriptionAttribute, 'Description').AsString);
      { not ok, output is '' }
      oAttr := GetClassAttribute(TMyClass, DescriptionAttribute);
      WriteLn(DescriptionAttribute(oAttr).Description);
      // WriteLn(oAttr.ClassName); // = 'DescriptionAttribute'
      ReadLn;
    end.
    

    我需要rtti属性。我希望用函数获取属性 GetClassAttribute() 但结果并非预期。

    功能结果 GetAttributePropertyValue() 正确(第一次写入),但函数的结果 GetClassAttribute() 是描述值为空的DescriptionAttribute。为什么?

    获取属性作为函数结果的正确方法是什么?

    TIA和问候 布兰科

    1 回复  |  直到 8 年前
        1
  •  4
  •   Stefan Glienke    8 年前

    问题是,如果TRttiContext超出范围,则在查询信息(包括属性)期间创建的所有RTTI相关对象都将被销毁。

    在属性类上放置析构函数时,可以验证这一点。

    引入的最新版本 KeepContext DropContext 上的方法 TRttiContext 您可以使用或只是将全局变量放在某个地方,并通过调用 Create 或者别的什么。我通常把 TRttiContext 使用RTTI将变量作为类变量输入到类中。

    保持上下文 DropContext 可用于可能没有全局 TRttiContext 实例,因为您使用的是其他类、方法和例程,它们有自己的 TRttiContext 参考-例如,请参见其在中的使用 System.Classes 期间的位置 BeginGlobalLoading 保持上下文 正在呼叫并进入 EndGlobalLoading DropContext .