An Interface You Can Count On

Using refcounted interfaces can be difficult, especially when introducing them into legacy code.  Unfortunately, interfacing is key to breaking dependencies and making code more testable.

There are only two approaches I have seen to debugging refcount issues:

1) Create a descendant of TInterfacedObject and override the _AddRef/_Release to log class information and the current refcount.  You could also use copy/paste inheritance (although I do not recommend making a habit of it), and change the implementations.

2) Create your own Interface like I did that exposes the RefCount and ClassName properties and make it the root ancestor for all interfaces used in your project instead of IInterface.  Then you can see the implementing class, and it’s refcount in the debugger, and log it as well if you see fit.  I wonder why TInterfacedObject doesn’t have such properties to begin with…

Here is an interface you can count on ;-) :


/// Interface that should be used as the ancestor
/// for all interfaces so we can see the refcount
/// when debugging without potentially altering it
/// by calling _AddRef/_Release.

IRefCountInterface = interface(IInterface)
['{95A446C2-A9E4-4355-8DDD-5B6854EBDBD0}']
function GetRefCount :Integer;
function GetClassName: string;
property RefCount :integer read GetRefCount;
property ClassName :string read GetClassName;
end;

6 Responses to “An Interface You Can Count On”

  1. Wagner Says:

    But do you use the official TInterfacedObject or you have your own class to override the ref counting behaviour (turn it off)? I mean, your code uses ref counting or manual create/destroy?

    I’m refactoring legacy code that uses manual Create/Destroy, so, using interfaces to decouple code means that I have to change this code to let ref counting take care of objects destructions.

    I wish I could use interfaces without changing the allocation pattern already used.

  2. Jeroen Wiert Pluimers Says:

    Too bad Delphi does not have interface helpers, but class helpers might make this easier. Need to give this a bit more thought.

  3. Stefan Glienke Says:

    Solution 2 would mean that you have to implement these 2 methods for every class aswell or use your own TInterfacedObject descendant as parent class.

    There is another solution though:
    (intf as TInterfacedObject).RefCount
    (intf as TObject).ClassName

    @Jeroen:
    Interface helpers would not do anything here because these functions are not related to the interface but to the implementing class. An interface helper just can access members of the interface it is helping but not any members of a class that is implementing the interface because that would break compatibility of the interface helper.

  4. Larry Hengen Says:

    @Wagner,

    I use both my own implementation of TInterfacedObject (of course using a different class name), and the interface shown so I get the best of both worlds.

    You can change the allocation pattern used with interfaces. Are you aware that TComponent descendants that implement interfaces are not refcounted?

  5. Steffen Binas Says:

    I released an open source tool to debug interface references visually. See here: https://github.com/AquaSoftGmbH/RefCountTracer

    It uses a similar approach of override _AddRef and _Release. But it logs the stacktraces and builds nice graphs afterwards.

  6. Larry Hengen Says:

    @Stefan,

    (intf as TInterfacedObject).RefCount

    is illegal in the evaluator. You have to use C style casts.

    ;-)

Leave a Reply