program Project15;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  System.Rtti, System.TypInfo;

type
  TRecord = record
  public
    AField: integer;
    constructor Init(test: integer);
  end;

  TOldObject = object
  public
    AField: integer;
    constructor Init(test: integer);
    procedure Fancy; virtual;    <<--- compiles
    class operator Implicit(test: TRecord): TOldObject; <<-- does not compile.
  end;

procedure IsObjectARecord;
var
  ARecord: TRecord;
  AObject: TOldObject;
  v: TValue;
  s: String;
begin
  v:= TValue.From(ARecord);
  case v.Kind of
    tkRecord: WriteLn('it''s a Record');
  end;
  ARecord:= TRecord.Init(10);
  AObject.Init(10);
  v:= TValue.From(AObject);
  case v.Kind of
    tkRecord: begin
      WriteLn('object is a record?');
      if v.IsObject then s:= 'true'
      else s:= 'false';
      WriteLn('isObject = ' + s);
      WriteLn('ToString says: '+v.ToString);
    end;
  end;

end;
{ TOldSkool }

constructor TOldObject.Init(test: integer);
begin
  AField:= 10;
end;

constructor TRecord.Init(test: integer);
begin
  AField:= 10;
end;

begin
  IsObjectARecord;
  Readln;
end.

The outcome of the test proc reads:

ARecord is a Record
AObject is a record?
isObject(AObject) = false
AObject.ToString says: (record)

However object <> record from a functionality point of view.
Object supports inheritance and virtual calls.
Record supports class operators.

Is there a way to tell TP5.5-objects and records apart using RTTI?
Is there even a need to tell them apart -ever-?

Note that I'm not planning to use object, I'm just enumerating types using RTTI so that my generic HashTable with pointers can clean up after itself properly.
Yes I know that object lives on the stack by default (or the heap with special effort) and do not normally need to be freed.

Bonus points if someone knows why virtual calls with TP5.5-objects no longer work, they used to work in Delphi 2007

有帮助吗?

解决方案

To the very best of my knowledge, in the eyes of Delphi's RTTI framework, an old-style object cannot be distinguished from a record. This program

{$APPTYPE CONSOLE}

uses
  System.Rtti;

type
  TOldObject = object
  end;

var
  ctx: TRttiContext;
  RttiType: TRttiType;
begin
  RttiType := ctx.GetType(TypeInfo(TOldObject));
  Writeln(TValue.From(RttiType.TypeKind).ToString);
  Writeln(RttiType.IsRecord);
  Readln;
end.

outputs

tkRecord
TRUE

其他提示

Old object is deprecated.

So you should not use it in conjunction with the new rtti.

First step of deprecation was to disallow virtual methods. Due I suppose to compiler regressions.

This is the Embarcadero decision to mimic C# and his struct / class paradigm. Wrong decision imho.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top