Solved

Casting question

Posted on 1998-07-29
15
438 Views
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 ?
0
Comment
Question by:asi
  • 5
  • 4
  • 2
  • +3
15 Comments
 

Author Comment

by:asi
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 ...

0
 
LVL 10

Expert Comment

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

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

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

Regards,
Viktor Ivanov
0
 

Author Comment

by:asi
ID: 1358949
No
what i"m looking for is
MyFunc (Sender:tobject);
var
CName: String
begin
  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
 begin
   ......
  end;

end;

10x anyway
asi
0
 
LVL 2

Expert Comment

by:kjteng
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?

 


0
 
LVL 1

Expert Comment

by:AJFleming
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)

eg:

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

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

function thingy(Sender : tObject)

var
  button : tButton;
  panel : tPanel;

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

Good luck,

Adam...
0
 
LVL 10

Expert Comment

by:Jacco
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);
begin
  with TObject.ClassType(Sender) do
     Caption := 'Hello there';
end;

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:

GetPropList
TypeData
TypeInfo
SetStringProp
GetStringProp
SetOrdProp
GetOrdProp

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

Let us know what you want exactly.

Regards Jacco
0
 
LVL 6

Accepted Solution

by:
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);
  begin
      with (Sender AS Sender.ClassType) do { I guess that's not what you're supposed to do *g*}
          abcd:=myValue;
  end;

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)
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 1

Expert Comment

by:AJFleming
ID: 1358954
Holger,

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 :)

Adam...
0
 
LVL 2

Expert Comment

by:kjteng
ID: 1358955
hoger:
"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.

0
 
LVL 6

Expert Comment

by:Holger101497
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:
TYPE
ClassA=Class
  price:integer;
  amount:integer;
  weight:real;
END;

ClassB=Class
  weight:integer;
  height:real;
  age:byte;
END;

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...
0
 
LVL 6

Expert Comment

by:Holger101497
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:
[1]
  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:
[2]
  E.StrategyType:=TClass((Sender AS TMenuItem).Tag);  {setting strategy}

where StrategyType is a Property of type TClass
[3]
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

[3]
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 :-(
0
 
LVL 6

Expert Comment

by:Holger101497
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!
0
 

Author Comment

by:asi
ID: 1358959
hi

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 :)
b_asi@inter.net.il

0
 
LVL 6

Expert Comment

by:Holger101497
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)!
0
 

Author Comment

by:asi
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.
     TComponent(Sender).Owner:=Self;"
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
b_asi@inter.net.il
0

Featured Post

Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

Join & Write a Comment

The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
Access reports are powerful and flexible. Learn how to create a query and then a grouped report using the wizard. Modify the report design after the wizard is done to make it look better. There will be another video to explain how to put the final p…
When you create an app prototype with Adobe XD, you can insert system screens -- sharing or Control Center, for example -- with just a few clicks. This video shows you how. You can take the full course on Experts Exchange at http://bit.ly/XDcourse.

705 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

Need Help in Real-Time?

Connect with top rated Experts

20 Experts available now in Live!

Get 1:1 Help Now