TPersistent + interface, Delphi - delphi

I need a class that is based on TPersistent (so it stores the RTTI) and includes default Interfaces handling (QueryInterface, _AddRef, _Release) ... what is the class name I'm looking for?

whoops, nevermind, just found it - TInterfacedPersistent. What a pity Delphi lacks this kind of docs FreePascal has. Thanks God it is quite compatible

Related

Delphi tstream: strange behaviour on create

I am new of Delphi. In the documentation of TStrem class, i read it is an abstract class.
So i think the compiler goes in error when i try to create it with
stream := TStream.Create();
Why not?
The Delphi language doesn't really have any formal concept of abstract class.
It is true that you can define a class to be abstract:
type
TMyClass = class abstract
end;
But you can perfectly well instantiate this class. In fact class abstract in Delphi is a feature used only by the long abandoned Delphi .net compiler.
A more useful definition of an abstract class is one that contains abstract methods. If you attempt to instantiate such a class, then a compiler warning will be emitted. Those warnings can be promoted to errors by way of a compiler option, if you wish.
When the documentation refers to TStream as being abstract it in fact means that it is "conceptually" abstract. In fact it does not even have any abstract methods, so by my definition above it is not abstract.
I'm really not sure why TStream does not contain abstract methods. I would suggest that the GetSize, SetSize, Read, Write and Seek should really be declared abstract. I suspect that if the class were being designed today then they would be declared abstract and likely they are not for historical reasons.
Instantiating TStream is a very common mistake made by programmers less experienced in the Delphi RTL. Once the mistake has been made a couple of times, the lesson is usually learnt. Unfortunately the system provides no easy way for this mistake to be flagged up. Each and every new programmer just has to learn the hard way.

FPC TList Specialization not supported

I am using Lazarus 1.0.4 with FPC 2.6
I am trying to create a TList of an own class (I just use string here, because it is more easy), but when I try to use
type
TStringList = specialize TList<string>;
it says "Specialization is only supported for generic types.
What am I doing wrong?
Might as well post it as answer, since it seems to have done the trick.
You need to use the fgl unit. See the Wiki at freepascal.org.

Interfaces in Lazarus/FPC: Multiple inheritance

I'm trying to create a shell extension to provide EXIF information for JPEG files in Windows Explorer "infotips", and am using Lazarus as this needs to produce an x64 DLL.
Does Lazarus support multiple inheritance with interfaces, and if so, how do I go about it?
for example, something like:
type
IInfoTips = interface(IPersistFile, IQueryInfo)
Thanks,
Mark
No, interfaces in FPC does not support multi-inheritance yet.
What you can do is letting the implementation class inherit from both interfaces:
type
TMyInfoTips = class(TInterfacedObject, IPersistFile, IQueryInfo)
But not at interface level, as you wish. Such statements won't compile:
type
IInfoTips = interface(IPersistFile, IQueryInfo)
You can only "inherit" from a single interface type.
Delphi does not support it either. Only the defunct Delphi for .Net compiler did... but because .Net/C# IR supports (and expects) the feature.
I'm also missing this feature in Delphi or FPC.
Both interfaces are defined in shlobj for Free Pascal/Lazarus, just like on Delphi. If symbols changed units during the Delphi lifetime, we try to put them in the more recent units, but there is a large backlog there.
All this should be largely Delphi compatible, maybe it is easier if you explained what exactly doesn't work like expected.
Added after Arnaud's comments:
No it does not. Objects implement interfaces in Pascal. I don't really understand why it is really important to do this anyway. Sure it is a bit of syntactic sugar, but since any delphi style interface implements Iunknown, you can just query an interface for another interface:
uses activex;
var x :IPersistfile;
y :IPersistStream;
begin
x.queryinterface(IID_IPersistStream,y);
end.

How can I get a dataset of in-memory objects?

Does anyone know of a TDataset descendant that works with Generics and RTTI, so that I can write code like this, and make use of data-aware components in the GUI? :
...
ds:TDataset<TPerson>;
...
procedure DoStuff;
begin
ds:=TDataset<TPerson>.create;
ds.add(TPerson.Create('A.','Hitler',77));
ds.add(TPerson.Create('O.','Bin Laden',88));
end;
This should be possible. The fielddefs can be created via RTTI because the exact type of the data is known. Values can also be automatically marshalled back and forth, so you can both view and edit data that's in a class or a record.
I hate having to write a lot of useless marshalling code, while the required information for that is available via RTTI already.
Or maybe somebody once wrote some sort of TEnumerable <-> TDataset adapter?
Does something like that exist, or should I start writing one?
...
The closest thing that I could find is an (excellent!) example by Marco Cantu, from Mastering Delphi 7, but the code itself doesn't make use of new language features like generics, the new RTTI system, or attributes, and it doesn't work with Unicode delphi. TDataset has changed since D7 too.
The TAureliusDataSet included in TMS Aurelius comes very close to that.
Take a look at EverClassy Dataset from Inovativa at www.inovativa.com.br/public.
another one is Snap Object Dataset http://digilander.libero.it/snapobject/
DotNet4Delphi by A-Dato Scheduling Technology from the Netherlands is good for you.
Quotes:
From Torry's Delphi
Hook up any collection to your data aware controls.
DotNet4Delphi implements many .Net collection classes, including
generic types like List<> and Dictionary<>. Different from their
Delphi counterpart is that our generic collections also implement the
non-generic interfaces (IList, IDictionary) allowing you to access
your collections in multiple ways. This opens the door to use any
collection as a data source for data aware controls which is exactly
what the (also included) TListDataset component provides.
It targets Delphi XE and XE2.
It's an open source initiative, Delphi rocks !!!
I have found a more relevant resource and can't help sharing it! So relevant that I think it deserves a separate post rather than a mere update in my first answer.
The Dduce library for Delphi XE2-XE6 makes use of TListDataSet<...> a generic dataset component that can be used to expose a generic list as a TDataSet.
The most relevant units pertaining to the implementation of the generic dataset are:
DDuce.Components.VirtualDataSet.pas (The original SO post is itself cited by the author within the source code as a reference among others!!!)
DDuce.Components.ListDataSet.pas
Class hierarchy:
TDataSet <= TCustomVirtualDataset <= TListDataset <= TListDataset<T>
Yes, it inherits lots of features... my only wish is to have at my disposal a version working with a lessen requirement (Delphi XE without most of the other bells and whistles).
Look and feel:

How do I determine the type of the implementing object of an interface

I'm attempting to write a unit test for a simple factory class that creates one of several possible implementing objects and returns it as an interface reference.
DUnit has a built in procedure, CheckIs(AObject: TObject; AClass: TClass; msg: string), that based on its name and the parameters it accepts should fail the test if the object's class type doesn't match the expected one. The only problem is it requires an object reference not an interface reference.
So I'm trying to use CheckTrue and perform the comparison in the body of the test but I'm not as familiar with Delphi's type checking support as I am with C#'s.
I know the is operator is out of the question since it only works with object references.
CheckTrue(LMyInterfaceReference {comparison here} TMyClass);
Any suggestions?
BTW, I'm using Delphi 2009 so I don't have access to the new RTTI support added in 2010+.
I'm wondering why you MUST have to test this... maybe you really don't have to.
But if knowing the underlying object of a Interface is a must, you have two choices:
Add a method to the interface which returns the underlying object, just a TObject, and implement this in each class just by returning self.
Hack a bit, for example using this Interface to object routine.
If you don't like hacks and don't feel like upgrading to Delphi 2010+ you may use an interface like this:
IImplementingObjectInterface = interface
function GetImplementingObject: TObject;
end;
Make sure your objects also implement this interface and use it to extract the implementing object. If you need to do this for a lot of objects you can define your own TInterfacedObject derivate that already implements this so you can simply change your inheritance and be done.
Barry Kelly (one of the main Embarcadero Delphi Compiler Engineers) wrote a nice An ugly alternative to interface to object casting this week.
It answers your question.
The fun is that Hallvard Vassbotn wrote a very similar piece of code back in 2004.
From Delphi 2010 on, you can just use an is check or as cast to go back from interface references to object references.
--jeroen

Resources