Avoid casting when passing objects through library code (in Delphi)

When developing libraries, I often resort to the following template, which I do not like, since it leads to a large number of ticks.

The main template:
Code using the library passes the object to the library, then the library passes the object back to the calling code. The calling code is forced to return an object, since the library returns a generic type. (Example abbreviated code below)

The library defines the following objects and functions:

TThing = Class End; TThingProcessor = Class Public Function CreateThing : TThing; Virtual; Abstract; Procedure ProcessThing (Thing : TThing); Virtual; Abstract; End; Procedure DoEverything (Processor : TThingProcessor); 

Then the calling code uses the library, overriding the objects and calling DoEverything, as follows:

 TMyThing = Class(TThing) Public X : Integer; End; TMyThingProcessor = Class(TThingProcessor) Public XSum : Integer; Function CreateThing : TThing; Override; Procedure ProcessThing (Thing : TThing); Override; End; Function TMyThingProcessor.CreateThing : TThing; Begin Result := TMyThing.Create; End; Procedure TMyThingProcessor.ProcessThing (Thing : TThing); Begin XSum := XSum + (Thing As TMyThing).X; //Here is the problem, the caller is forced to cast to do anything End; 

The processor class is also a TThing factory. The library guarantees that it will only pass TThings to the corresponding twingprocessor that created them, so it works, but is not type safe. Although the code above is a little silly in that it doesn't actually do anything, it shows why ProcessThing cannot just be switched to TThing and be polymorphic - the XSum variable needs to be updated.

How can I restructure the code to make the throw unnecessary? I need to save the library code separately, but be able to accept any types.

Edit: Due to the proposal, I changed hard-cast to as-cast, so it will at least throw an exception instead of failing in case of inappropriate types.

+4
source share
3 answers

Are you using Delphi 2009? This is very useful for generics. Change your ads to:

 TThingProcessor<T: TThing> = Class Public Function CreateThing : T; Virtual; Abstract; Procedure ProcessThing (Thing : T); Virtual; Abstract; End; TMyThingProcessor = Class(TThingProcessor<TMyThing>) Public XSum : Integer; Function CreateThing : TMyThing; Override; Procedure ProcessThing (Thing : TMyThing); Override; End; 

No longer casting.

+3
source

You must rebuild your code. If you are doing a lot of β€œTThing” creation, then it should have an ancestor class with the IRS processing method declared as virtual, then you just work with the ancestor. As a rule, you can always define a common β€œbase class” when you make similar calls for very different classes. If you cannot create such a class structure, use the interface to define your processing requirements and connect this interface to your TThing.

In the latter case, when you cannot escape the cast, use the following for readability and debugging ...

 procedure Something( ASender : TObject ); var MyThing : TMyThing; begin MyThing := ASender as TMyThing; MyTHing.DoSomething; MyThing.DoSomethingElse; end; 
+3
source

If the TMyThingProcessor will only accept TMyThing objects, and the underlying TThing objects will not work, do not try to make it polymorphic. Declare ProcessThing with the reintroduce directive ; , rather than override directives ; .

Also, if you have one, the features of Generics Delphi 2009 help in reducing false tricks in certain situations.

+1
source

All Articles