The Fundamental Limit
In C# (especially with tools like PostSharp) or Java (Spring AOP), attributes can trigger code injection at compile-time or load-time. In Delphi, attributes are strictly information. They sit in the binary, waiting to be read.
Delphi Native Behavior
Passive[MyAttribute]
Just data compiled into the DCU/EXE.
Method Code
Executes normally. Ignores the attribute completely unless asked.
AOP (Achievable via Frameworks)
Active[LogExecution]
Intercepts the call *before* it hits the object.
Interceptor Logic
Executes Pre-Processing -> Calls Method -> Post-Processing.
No Compile-Time Injection
Delphi compilers do not support "weaving" (modifying IL/Assembly during build) based on attributes out of the box.
Runtime Only
All attribute discovery happens at runtime using System.Rtti. This adds a performance overhead.
Interface Based
To truly change behavior, you essentially must use Interfaces + TVirtualInterface to wrap the target class.
The RTTI Extraction Loop
Before building AOP, you must understand how to read the data. This is the "Manual" approach.
In modern Delphi, TRttiContext is your gateway.
// Click steps on the left to see the code explanation
type
TMyAttribute = class(TCustomAttribute)
// ...
end;
[TMyAttribute('Hello World')]
TMyClass = class
end;
TCustomAttribute. Annotate your class or method using brackets [].
Implementing AOP (The "Active" Part)
To answer your question: Can it change functionality? Yes, but you must build a "wrapper".
The standard way in Delphi is using TVirtualInterface.
This allows you to create an object at runtime that intercepts method calls (Invoke) similar to RealProxy in .NET.
Configuration
Annotates method with metadata.
Requires 'UserRole' validation.
Execution Pipeline (TVirtualInterface)
// Waiting for ICalculator.DoCalculation()...
How this works in Delphi Code:
- You define an Interface (e.g.,
ICalculator). - You create a factory that returns
TVirtualInterface.Create(TypeInfo(ICalculator), InvokeHandler). - The
InvokeHandlerclosure inspects the Method RTTI for your Attributes. - If
[Log]is found, it runs logging code before invoking the actual object.
Performance & Limitations
Because Delphi Attributes are not compiled into direct jumps, using RTTI has a cost. Using Virtual Interface interception has a higher cost.
The Cost of "Magic"
-
Direct Call Zero overhead. CPU jumps directly to address.
-
RTTI Lookup (Cached) Checking
TRttiContextis fast if cached, but slow if inspecting types every call. -
AOP Interception
TVirtualInterfacerelies onSystem.Rtti.Invoke, which wraps arguments in TValue. It is significantly slower than direct calls (microseconds vs nanoseconds).