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
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
/sub
ReplyDeleteNot easily. You have to manually find out by looking at the VirtualIndex property and/or the class VMT.
ReplyDeleteWhat do you mean by, "has an override"?
ReplyDeleteI 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.
ReplyDeleteIf no Export method override existed, I could assume the reference as read only.
This sounds like a pretty dire approach to solving your problem, in my opinion.
ReplyDeleteIt'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.
ReplyDeleteSure. 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/-:
ReplyDeleteTo 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.
ReplyDeleteTurned 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.
That looks like a terrible idea to me
ReplyDeleteWhat I have done (simplified), with RTTI is:
ReplyDeleteif (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...
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.
ReplyDeleteDavid 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.
ReplyDeleteYour 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.
ReplyDeleteThat's not really pertinent to my original question ;)
ReplyDeleteYou 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."
ReplyDeleteIn 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.
ReplyDeleteOK, I'll make sure never to offer you advice beyond the tight confines of any questions that you ever ask. Fine by me.
ReplyDeleteDavid Heffernan - "That looks like a terrible idea to me" and "It just smells really badly as a solution to a problem" is advice?
ReplyDeleteI 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.
ReplyDeleteI liked your answer Asbjørn Heid :D
ReplyDelete