RTTI and method overrides

RTTI and method overrides
Is it possible to see that a specific method in the (current) class has an override, using RTTI?
Update: See my comment 12:02 - it was solvable without using RTTI or VMT trickery

Comments

  1. Not easily. You have to manually find out by looking at the VirtualIndex property and/or the class VMT.

    ReplyDelete
  2. What do you mean by, "has an override"?

    ReplyDelete
  3. I was thinking of having "import/export" methods that could be used for manually copying values to/from a reference - but if those were not overridden for the class - I would try to match properties by name/type.
    If no Export method override existed, I could assume the reference as read only.

    ReplyDelete
  4. This sounds like a pretty dire approach to solving your problem, in my opinion.

    ReplyDelete
  5. It's only dire if it is not reliable. When you are potentially facing edit forms in the number of hundreds - you really start to appreciate anything that will reduce the amount of boilerplate code.

    ReplyDelete
  6. Sure. But you want it to be robust. Digging around in the VMT isn't. I think attributes are what are intended to be used for such boilerplate reduction tasks.

    ReplyDelete
  7. To clarify - I only want to detect that there is an override in the current class class instance for a method defined in it's base class.

    Turned out that this was a LOT simpler than I thought - and I didn't need to fool around with neither VMT nor RTTI.

    unit DetectOverride;

    interface

    type
      TRootClass = class
      private
        FHasImport: boolean;
        FReference: T;
        function GetReference: T;
        procedure SetReference(const Value: T);
      protected
        procedure ImportByRTTI; virtual;
        property HasImport: boolean read FHasImport write FHasImport;
        property HasExport: boolean read FHasImport write FHasImport;
      public
        constructor Create; virtual;
        procedure ImportReference; virtual;
        procedure ExportReference; virtual;
        property Reference:T read GetReference write SetReference;
      end;

      TDerivedClass = class(TRootClass)
      public
        procedure ImportReference; override;
      end;

    implementation

    { TRootClass }

    // This is where the discovery happens
    constructor TRootClass.Create;
    var
      vm: procedure of object;
    begin
      Inherited;
      vm := Self.ImportReference;
      HasImport := TMethod(vm).Code <>@TRootClass.ImportReference;
      vm := Self.ExportReference;
      HasExport := TMethod(vm).Code <>@TRootClass.ExportReference;
    end;

    procedure TRootClass.ExportReference;
    begin
      // Manually copy fields internal properties to reference
    end;

    function TRootClass.GetReference: T;
    begin
      if HasExport
       then ExportReference;
      Result := FReference;
    end;

    procedure TRootClass.ImportByRTTI;
    begin
      // Do RTTI magic
    end;

    procedure TRootClass.ImportReference;
    begin
      // Manually copy fields from Reference to internal properties
    end;

    procedure TRootClass.SetReference(const Value: T);
    begin
      FReference := Value;
      if HasImport
       then ImportReference
        else ImportByRTTI;
    end;

    { TDerivedClass }

    procedure TDerivedClass.ImportReference;
    begin
      // In this class, HasImport will be True after create
    end;

    end.

    ReplyDelete
  8. That looks like a terrible idea to me

    ReplyDelete
  9. What I have done (simplified), with RTTI is:

    if (FRttiMethod.DispatchKind = dkVtable) then
    begin
      LKind := '; virtual';

      if (FRttiMethod.Parent.BaseType.GetMethod(FRttiMethod.Name).DispatchKind = dkVtable) then
      begin
        LDispatchKind := '; override';
      end;
    end;

    It could be over simplifying things and getting false positives but it seems to be working...

    ReplyDelete
  10. Just to be clear, when you wrote class you meant instance. And by has an override you mean to compare the method specified by the instance with the method specified by some base type.

    ReplyDelete
  11. David Heffernan What is a terrible idea? My way of spotting an method override - or the concept of using RTTI to match properties? For the latter, about as terrible as LiveBindings, I guess.

    ReplyDelete
  12. Your way to detect that the method bound to this instance is different from that defined in some base type is fine. It just smells really badly as a solution to a problem.

    ReplyDelete
  13. That's not really pertinent to my original question ;)

    ReplyDelete
  14. You don't mean that. You don't mean that when you ask a question you only ever want a direct answer to it, and you do not want anyone to expand on the issues around the question. You absolutely do want that. You want us to say, "well, the answer to your question is X, but you've probably asked the wrong question, because of Y."

    ReplyDelete
  15. In this case, I really do mean that. "Because of Y" is not really relevant to the original question. How to do it is relevant. Why I want to do it, really is irrelevant - and it will be up to me to evaluate the risk/reward in the context of where I would be using answer X.

    ReplyDelete
  16. OK, I'll make sure never to offer you advice beyond the tight confines of any questions that you ever ask. Fine by me.

    ReplyDelete
  17. David Heffernan - "That looks like a terrible idea to me" and "It just smells really badly as a solution to a problem" is advice?

    ReplyDelete
  18. I understand. I'll refrain in the future. I'll make sure that I only ever address the direct question that you ask, and never stray from the confines of that question.

    ReplyDelete
  19. I liked your answer Asbjørn Heid​ :D

    ReplyDelete

Post a Comment