Craig Stuntz
comments on my
remarks
about interfaces in Delphi / Win32:
Regarding interfaces, I'd argue that Delphi Win32 interfaces are more
similar to .NET interfaces than COM interfaces are to COM+ 2.0 (a.k.a.
.NET) interfaces insofar as they don't completely dictate lifetime
management. In Delphi Win32 I can (and frequently do) override
reference counting and use interfaces to provide multiple interface
inheritance of classes without reference-counted lifetime management
of instances.
Sure. Delphi/Win32's interfaces are a superset of COM interfaces; they
include support for native Delphi types (such as AnsiString), and when one
is working in single-language / single-vendor (taking BCB into account)
environment, it can be useful to discard the language-neutral COM conventions.
That doesn't stop the Delphi compiler from performing all the refcounting
operations anyway, though.
I can't cast from an interface to an object, but in
other respects it's pretty similar to what I do with interfaces in
.NET. The underlying mechanisms are very different, yes (e.g., GUIDs
as IIDs), but in the end I find myself doing similar things in code.
When you say interfaces are different in Delphi Win32 and .NET you
seem to be talking about lifetime management.
I'm talking about slightly more than that. I'm talking about the basic
services that IUnknown provides: lifetime management (AddRef and Release)
and interface negotiation (QueryInterface). All Delphi/Win32 interfaces derive
from an interface that supports these three operations (whether it's IInterface
or IUnknown depending on version). Delphi/Win32 implements interface casting
(in so far as it does at all, excluding Supports() etc.) through calls to
QueryInterface, via 'as'. Delphi/Win32 doesn't support 'as' casting unless
the interface has a GUID, a COM-ism. Delphi/Win32 classes can dynamically
change which interfaces they support (within or without COM rules) by explicitly
implementing QueryInterface() - that won't work in .NET (I use IServiceProvider for this).
All COM interfaces consumed in Delphi in the orthodox way (ignoring the old
Delphi 2 stuff) are also Delphi/Win32 interfaces. Delphi/Win32 interfaces and
COM interfaces are basically made of the same "stuff", with the same binary format.
.NET interfaces are entirely different; they're a runtime feature, and they aren't
a binary standard. They're not ref-counted. They don't have the same layout. Casting
is defined by the implementing class, and can't be dynamically changed (RealProxy etc.
aside). They don't require GUIDs for full support. COM interfaces get wrapped in runtime
callable wrapper (RCW), rather than being actual .NET interfaces.
But the lifetime
management features in Delphi Win32 are something I generally try to
work around because (1) I mostly don't use them for COM and (2) I
find having two wildly different lifetime management schemes
coexisting inconvenient. When I work in .NET I use the GC; I would
find doing a mixture of GC and explicit allocation / disposal messy.
Similarly, I only want my object instances reference counted in Win32
when I can't avoid it, like when I must use COM. Otherwise I want to
do things explicitly, for the sake of consistency.
Sure - but you have to do this yourself! Delphi's TInterfacedObject, the normal
base for a class supporting interfaces, implements COM rules. I think it
can even be useful to work within the COM rules too, when restricted to Win32-only
code, since the automated ref-counted GC supports shared ownership fairly
well.
No comments:
Post a Comment