Casting question

Posted on 1998-07-29
Last Modified: 2012-05-04
can i Make a casting on parameter (in function) like Sender:Tobject
and According to the ClassName method
Cast the Sender to that object ?
Question by:asi
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 5
  • 4
  • 2
  • +3

Author Comment

ID: 1358947
to make the question more clear

> the sender can be 10000 type of object in a different type , the common between all thos objects is (just) that they have property named abcd , i cant start ask 10000 condition and just then make an cast ...

LVL 10

Expert Comment

ID: 1358948
Is this what you are looking for...

procedure TForm1.FormClick(Sender: TObject);
var i : Integer;
   for i := 0 to ComponentCount - 1 do
        if TButton(Components[i]).ClassName = 'TButton' then
          TButton(Components[i]).caption:= Inttostr(i);

.if it isn't ...well...

Viktor Ivanov

Author Comment

ID: 1358949
what i"m looking for is
MyFunc (Sender:tobject);
CName: String
  CName :=Sender.ClassName;
 with CName(Sender) do
// i.e. to make casting to the sender according to CName
// again the sender can be  from 1000000 object type
// so i can not do like u said if  ... then ...CAST


10x anyway
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!


Expert Comment

ID: 1358950
It is not practical to test 1000 cases of the classname and then cast the object accordingly. I don't think there is anything thing function like ConvertToTypeByNameOf( 'tButton', sender).

But why you want to do that? What is the actual problem that lead you think of doing this? Can virtual type of component solve the problem?



Expert Comment

ID: 1358951
Surely you don't need to know exactly what the component is if it's not one of the classes you're interested in you can just ignore it, or throw an exception or whatever. That then makes it practical to use a case statement (with some sort of function to convert your string classname into an ordinal that a case can deal with)


  cnUnknown : integer = -1;
  cnButton : integer = 1;
  cnPanel : integer = 2;
// etc

function ClassNameToInt(ClassName : string) : integer
  if ClassName = 'tButton' then
      ClassNameToInt := cnButton
  else if ClassName = 'tPanel' then
      ClassNameToInt := cnPanel
    ClassNameToInt := cnUnknown;

function thingy(Sender : tObject)

  button : tButton;
  panel : tPanel;

  // do something
  case ClassNameToInt(Sender) of
    cnButton : button := Sender as tButton;
    cnPanel : panel := Sender as tPanel;
    raise EOhBuggerSomethingWentWrong.Create('unknown sender class');
   // do something else

Good luck,

LVL 10

Expert Comment

ID: 1358952
Delphi is a strongly typed language. That is the reason that what you are trying to do is not possible. The compiler wants to know the type of object is within the WITH clause otherwise it will not compile.

If Delphi would not have been "type-safe", for example the following would be possible to compile but would give erroneous code:

procedure SetControlCaption(Sender : TObject);
  with TObject.ClassType(Sender) do
     Caption := 'Hello there';

Now if Sender would be a TParam (which has no caption) the program would compile but not run. That is the reason why it is not permitted in Delphi.

A good way of handling this are described above. The case statement is often used for that or a nested if construction.

Another good thing is to use base types. For example TWinControl or TControl. You can cast any object derived from TControl to TControl and access the properties and methods of a TControl.

If you want to set the Caption property of all possible classes that have such a property you could use the TypInfo unit to check if the class has a certain property and then set it using functions/procedures in the TypInfo unit.

Functions of interest in TypInfo are:


(If you want an example on how to do this, let me know)

Let us know what you want exactly.

Regards Jacco

Accepted Solution

Holger101497 earned 30 total points
ID: 1358953
Sorry for locking this question without (yet) giving a 100% correct solution (I'm in the office and don't have Delphi docs with me :-))

However, I can give you two approaches:
1) How do you know that all the objects that could be passed in sender have property abcd in common? Do they have a common ancestor? In that case, you can easily cast to that ancestor and check the component, e.g. TComponent(Sender).Owner:=Self;
2) I seem to remember that there is a property **ClassType** (rather than ClassName) and I've done very interesting stuff with that!! (I'll try to find and post it for general amusement *g* - I casted different class types to integer (!!) values and stored them in menuitem-TAG-fields. Then when the menu item was clicked, I casted them back to TClassType to instatiate an object of that class! Basically the same problem you have: I didn't want to have ten IF-statements to check for the classes. Also, my menus were very flexible and could even handle and instatiate types that didn't exist when the units were compiled :-))
Therefore, I'm pretty sure I can answer your question as soon as I get home.
In the mean time, this "could" work:

MyFunc (Sender:tobject);
      with (Sender AS Sender.ClassType) do { I guess that's not what you're supposed to do *g*}

Good luck!
P.S.: ClassType (if that's what it's called) returns a value of type TClassType and as far as I know, it's really a pointer to that class' VMT (which is unique for each class)

Expert Comment

ID: 1358954

can I just add my thanks for pointing out that property! I'd seen it before but hadn't thought of how to use it; I like the idea of storing references in tags :)

I did have a thought though, ClassType returns a tClass (according to the D2 docs) which is the ultimate ancestor of all classes so you're really back at the start again. You've got an object, stored as an abstract ancestor (tClass rather than tObject in this case,) but you've still got to cast it to something if you want to get at any methods not defined by tClass (ie, just about anything.) I think the whole crux of the matter is that you can't write the code blind (unless you really like n-thousand case statements,) you have to know what you want and expect the object to be.

good luck, and thanks again for pointing that one out... Now, where to use it :)


Expert Comment

ID: 1358955
"my menus were very flexible and could even handle and instatiate types that didn't exist when the units were compiled"

Interesting. I also want to know how did you do that. For one of my project, I need to create record structure at run time. May be your code would help.


Expert Comment

ID: 1358956
Hello all :-)

Sorry, but this week's so busy I didn't get around to digging out that old code... I will (almost :-) definitely have the time to post something tomorrow, maybe even today.

AJFleming got me thinking, though... and he has a good point with his statements about TClass... the problem is not so much runtime-behavior as compiler-problems... If you really don't have ANY idea what you're getting, any code like SomeNiftyCasting(Sender).abcd won't compile without problems because the compiler doesn't know if the sender even HAS that property... compilers like translating all "symbolic information" (such as the NAMES of the properties) to addresses - absolute or relative (to the object's base address).

So what if you have these two classes:


How would the compiler know about the relative address of "weight"? Trying to access a field of the same name in two completely unrelated classes would be terrible programming style... nothing (or at least not so much) against Visual Basic, but I think that's the language for doing that kind of stuff... any interpreted language (e.g. JavaScript) can do those things, but a highly (?) optimizing compiler normally won't!

Now did I write complete nonsense and made wrong promises? No, not quite - I just assumed proper programming style and my approach still gives you a lot of flexibility. The thing is that I didn't have to access the properties of completely unknown classes, I just needed to instantiate them without caring too much about the type (return them as a TObject...).

So for the specific question asked here, we're back to my first comment:
"1) How do you know that all the objects that could be passed in sender have property abcd in common? Do they have a common ancestor? In that case, you can easily cast to that ancestor and check the component, e.g. TComponent(Sender).Owner:=Self;"

ASI: Please answer this one before I post a code snippet:
How can you be absolutely sure that the sender will always have a property named abcd?? In "normal" abject oriented programming, the reason is (or at least definitely should be) a common ancestor, e.g. the sender could be any Control and you know that they all have a property "Left". Even if they descend from two ancestors, it wouldn't be so bad - you can check for that... If all those classes are completely independent from each other, something is definitely very wrong with your code...

Let me know and I'll try to post a solution for you later today or tomorrow...

Expert Comment

ID: 1358957
Hello asi?? I can't post a complete solution if you don't answer my questions...

For everybody else who's waiting for some tricks *g*
Oh boy... it's always more complicated than it looks to get some working code out of a project. Of course the code that's needed for a "demo" is in at least 5 different procedures :-(

But I'll try... this was for implementing different optimization algorithms that could be switched at runtime. Code first, explanation below...

In the Form.Create, I do this:
  miRandomFit.Tag    :=integer(TRandomFit);     {this puts me on the }
  miFirstFit.Tag     :=integer(TFirstFit);      {"safe" side: I don't}
  miBestFit.Tag      :=integer(TBestFit);       {know if this value is}
  miPlanningAhead.Tag:=integer(TPlanningAhead); {and will remain constant}

in the "CheckMenuItem", I do this:
  E.StrategyType:=TClass((Sender AS TMenuItem).Tag);  {setting strategy}

where StrategyType is a Property of type TClass
PROCEDURE SetStrategyType(NewType:TClass);
  IF (Strategy=NIL) OR (NewType<>StrategyType) THEN Strategy:=(NewType.Create AS TStrategy); //SetStrategy takes care of disposing old strategy

Section [1] initializes the tags to the integer representation of the Classes! Note how a TYPE can be cast to an integer!!!

Section [2] takes the tag that was assigned to the MenuItem and converts it back to a class. This "class" is assigned to the property Strategytype

which, in the SetStrategyType, instantiates an "object" of the class (note this: NewType.Create; !) and assigns it to the "Strategy-property". The object is cast to the appropriate type by (Newtype.Create AS TStrategy);

Any questions?? I'm afraid it sounds more complicated than it is, but it's hard to explain...
Basically, the whole trick could be done by
NewStrateyObject:= (TClass((Sender AS TMenuItem).Tag).Create) AS TStrategy;

I hope you like this code snippet, although it's off-topic and maybe not soo helpful for asi.

asi: Please answer my questions above so I can post some code that works for you!

If anybody has any questions: Go ahead *g* - this is not about those 30 points anyway... BUT I'm rather busy and might be a bit slow :-(

Expert Comment

ID: 1358958
ok, great...
take a look at my profile and you'll know why I won't answer another question for asi!

I really don't care so much about points any more - that's why I answer questions for just 30 points or even no points at all - but I DO care about my grades and don't like ruining my profile for some lousy points!

Still: If anybody has any questions - go ahead!

Author Comment

ID: 1358959

sorry , The question u answer was very comprehensive and they are deserve more point !
if u have any idea how can i upgrade your mark & point please tell me about it

man while
please , be happy

Asi :)


Expert Comment

ID: 1358960
well, first of all: You can NOT upgrade the mark and that's the problem - you COULD give me some extra points by asking a "fake" question exclusively for me, but as I said, that's not what I am/was mad about.

I invest some time to help other people (I can't buy anything for those points, you know) and I'd like them to appreciate the help, that's all... (and that includes assigning a grade).

So, I don't really feel that I have solved your problem because I didn't have all the information I needed. If you still want it to be solved, you should answer the questions I asked about 4 weeks ago (July 31st)!

Author Comment

ID: 1358961
hey holger !

your question was
"1) How do you know that all the objects that could be passed in sender have
     property abcd in common? Do they have a common ancestor? In that case, you
     can easily cast to that ancestor and check the component, e.g.
the story was like that i had a few object some was override on Tlist and Some just from Tobject etc...
after some time i want to add for each ot thos object property named "abcd"
thos objects might be pass  to some function that KNOW (by default- i.e. that thos object parameter that this function recive has object with "abcd" property )
i knew ofcours that i can make common ancestor , but since thos object was based on different "parent" such a task was too much long ...
since i was under time presure , i finaly made this changes and the above question was very much intresting me , theoreticly;
hope i unsewer your question
one more thins i add a fack quetioin named/title "abcd" u may answer your next question there and i'll give u the grade
10x in advance

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
I've attached the XLSM Excel spreadsheet I used in the video and also text files containing the macros used below.…

710 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question