Why does this object need to be cast?

H

Hazz

In this sample code of ownerdraw drawmode, why does the '(ComboBox) sender'
line of code need to be there in this event handler?
Isn't cboFont passed via the managed heap, not the stack, into this
cboFont_DrawItem event handler? Why does it need to be cast? -hazz

,.................
cboFont.Items.AddRange(FontFamily.Families);
}

private void cboFont_DrawItem(object sender,
System.Windows.Forms.DrawItemEventArgs e) {

ComboBox cboFont = (ComboBox) sender; .........,
 
I

Ignacio Machin \( .NET/ C# MVP \)

Hi,

The signature of the event is EventHandler( object sender, EventArgs e )

meaning that you have to cast sender to the correct type.

You will find this situation almost everywhere.

Cheers,
 
H

Hazz

Thank you Ignacio but I guess I didn't ask my question clearly.
If the eventhandler will never handle anything other than (in this case)
comboboxes, why do I need to cast to comboboxes?
Is it because sender is of a generic object type? Does the runtime not know
that this is an object of type combobox?
If I am passing by reference rather than by value, doesn't the heap retain
the combobox info? Or is this a metadata thing?
Is that why I also often see the 'TypeOf' keyword at the beginning of a
method, to test to see if perhaps this object that is passed in as an
argument is of the type Combobox? Or is this for some other reason?
thx, -hazz
 
M

Michael S

Hazz said:
Thank you Ignacio but I guess I didn't ask my question clearly.
If the eventhandler will never handle anything other than (in this case)
comboboxes, why do I need to cast to comboboxes?
Is it because sender is of a generic object type? Does the runtime not
know that this is an object of type combobox?
If I am passing by reference rather than by value, doesn't the heap retain
the combobox info? Or is this a metadata thing?
Is that why I also often see the 'TypeOf' keyword at the beginning of a
method, to test to see if perhaps this object that is passed in as an
argument is of the type Combobox? Or is this for some other reason?
thx, -hazz

First thing, don't use the word generic to describe something general. This
will just make you confused when you move to .NET 2.0 and actually have
generic types.

As for your problem. The event handler is defined by a general delegate that
is used all over the .NET framework for simple events. Hence even though
your combobox knows its type, the delegate does not and you must resort to
downcasting.

The combobox triggers the event and sends itself as sender and in the
process it gets upcasted to Object. In order to access the the instance as
more than a Object you must downcast it to an appropriate type. If you only
need it's name you could downcast to Component and if you need it's position
you could downcast to Control. However, if you want to know it's selcected
item you need to downcast to ComboBox.

Downcasting is dangerous as you must know what type the instance can be cast
to. This is what generics will try to solve for us with parameterized types.
It's a very nifty thing to have.

..NET is not only about managed data (ie having a garbage collector) but also
managed code. Hence if you try to downcast an instance of a ComboBox from an
Object-reference into a StringBuilder the Common Language Runtime (CLR) will
check if it's an ok cast and throw a InvalidCastException if you tried.

The same is not true for unmanaged code like C++ and Delphi. If you make an
illegal cast you really screw things up and you wind up with a reference
pointing to one type of object using methods of the wrong class, typically
giving you the infamous 'General Protection Fault' or 'Access Violation'
exception when the code being called makes non sense. This is also why C++
and Delphi sport much better performance than .NET and Java. The former
don't check what we do and the latter hold our hands while we do it.

Casts in C# is actually methods, called cast operators, even though they get
very much optimized by the CIL-compiler for most types in the Common Type
System (CTS).

C# introduces two types of cast operators; implict- and explicit-casts.
Example with cast operators on System.Byte and System.Int32:

myInt = myByte; //implicit cast, a 8-bit can always become an 32-bit
myByte = (Byte)myInt; //explicit cast needed as an int may contain a large
value which throws an exception.

If you define a class in C# you can supply it with your own cast operators.
Hence a subclass called MyComboBox could very much become a StringBuilder,
if you'd want. =)

But note the smiley. You should be very careful before overloading
operators, even cast operators. Cast operators should only be used when
there is a natural and simple conversion from one type to another. Note how
a System.Byte can be cast to System.Int32 without effort and therefor
supports a cast operator for it, while making it into a string involve
actual work and so you must call the method.ToString()

Hope this made you less confused.=)

- Michael S
 
H

Hazz

Thank you Michael!
Having just attended an all day 'generics' education day, your point is well
taken about sloppy use of the term 'generic.'
Moreover, your explanation helped me to better understand why I would want
to use generics rather than 'just' how.
I think I followed you very well with your explanation. If you are so
inclined, would you say anything about the 'typeof' keyword as it is often
used and how that might change with the use of .NET 2.0's generics? Or is
this apples and oranges?
In any case, thank you so much for the explanation you already
rovided. -hazz
 
M

Michael S

Hazz said:
Thank you Michael!
Having just attended an all day 'generics' education day, your point is
well taken about sloppy use of the term 'generic.'
Moreover, your explanation helped me to better understand why I would want
to use generics rather than 'just' how.

- Thanks. I've held a couple of informal lectures on generics, and it's when
I mention the problem with downcasts people get it. Generics will save us
alot of stupid downcast-bugs in .NET 2.0
I think I followed you very well with your explanation. If you are so
inclined, would you say anything about the 'typeof' keyword as it is often
used and how that might change with the use of .NET 2.0's generics? Or is
this apples and oranges?
In any case, thank you so much for the explanation you already
ovided. -hazz

I seldom see the 'typeof' keyword in code but often the 'is' keyword. Always
something like this:

if (myObject is StringBuilder)
{
((StringBuilder)myObject).Append("I think I am doing the right thing!");
}
else
{
throw new Exception("Oops, I did the wrong thing. I hate this f**king
job!");
}

The above code may look sound for a Delphi or C++ developer where a direct
cast can have severe side-effects, but the .NET framework protect us. Many
people still don't get the value of managed code. Hence the above code is
just bloat and I would rather see just this:

((StringBuilder)myObject).Append("This just should work or I have no brains.
..NET will stop me if I'm stupid!");

In .NET both pieces of code do the exact same thing, appends a string to a
StringBuilder or throw an exception if it is in error. But the latter is
more neat as it:

1) is short and to the point.
2) says to the maintainer that it really wants a StringBuilder and have no
'what-if' or 'why-not' conditions.
3) will not throw the most general Exception there is, with a silly
errormessage that might reach the user.
4) will have the CLR throw a very defined InvalidCastException for us, and
by so showing us that we have a bug.

My point being, do not code checks in .NET that the CLR will check for you.
If .NET throws an excpetion, it's a bug. Log it, mail it, do whatever stuff
you want with it, but don't protect yourself from it.

My true point being: if you're gonna downcast; - Be bold and make sure you
do it right!

- Michael S
 
J

Jon Skeet [C# MVP]

My point being, do not code checks in .NET that the CLR will check for you.
If .NET throws an excpetion, it's a bug. Log it, mail it, do whatever stuff
you want with it, but don't protect yourself from it.

That's only true if the caller is definitely meant to pass in an
instance of the specific type though.

Consider a method which copies the contents of one stream to another -
if a MemoryStream is passed in, the MemoryStream.WriteTo method is the
fastest way of going; otherwise, you need to copy block by block. That
could be written:

MemoryStream ms = sourceStream as MemoryStream;
if (ms != null)
{
ms.CopyTo (destStream);
}
else
{
...
}

Nothing wrong with that.

Where you're going to throw an exception if the object is the wrong
type, there may still be value in throwing a different exception to the
default InvalidCastException - for instance, throwing an
InvalidArgumentException may be more appropriate (and allows you to
specify which parameter was wrong).
 
M

Michael S

Jon Skeet said:
That's only true if the caller is definitely meant to pass in an
instance of the specific type though.

-It typically is just so for applications. When we build applications we
only sew things up for which with managed code we have protection. For
writing low level classes, overiding operators and such, Exception handling
should be mandatory. But for applications, we should rely on the protection
and the documentation there is.

This is the Java pitfall with checked exceptions. It goes like this:

When I write a method in Java, I might receive a reference type. Hence I
better by a good java-dev and check for null first and type then. This
implies I have to throw two checked exceptions. But the one calling the
method knows very well that the object is there and is of the right type.
But stand no chance no less. The caller must do a silly try/catch or forward
it upwards which makes even less sense.

The caller will sport code that implies that something may go wrong when it
cannot possibly do so.

I like Anders Hjelsbergs view on this. - Never force a caller to handle
exceptions. Good code have a finally/catch ratio of 10 to 1.
Consider a method which copies the contents of one stream to another -
if a MemoryStream is passed in, the MemoryStream.WriteTo method is the
fastest way of going; otherwise, you need to copy block by block. That
could be written: ---
*snip*

- Nothing wrong if you're writing a general component. But if you're
building an application, you fool the maintainer as to beleive that the
stream may or not work, when it always does. Hence the protection is not
only overkill, but may take the maintainer on a short, but dead end, trail
while debugging.

Where you're going to throw an exception if the object is the wrong
type, there may still be value in throwing a different exception to the
default InvalidCastException - for instance, throwing an
InvalidArgumentException may be more appropriate (and allows you to
specify which parameter was wrong).

- This may be true for C++ and Delphi, as bugs in a release compile often
just yields an access violation and a hexcode address. But for managed code,
most developers just want to find the .cs file and line-number to fix the
darn simple bug.

Jon Skeet - <[email protected]>
http://www.pobox.com/~skeet
If replying to the group, please do not mail me too

- Thanks Mr. Skeet. Looking forward to your reply.

- Michael S
 
J

Jon Skeet [C# MVP]

Michael S said:
-It typically is just so for applications. When we build applications we
only sew things up for which with managed code we have protection. For
writing low level classes, overiding operators and such, Exception handling
should be mandatory. But for applications, we should rely on the protection
and the documentation there is.

Well, I'm in favour of sparingly used checked exceptions, but there we
go.
This is the Java pitfall with checked exceptions. It goes like this:

When I write a method in Java, I might receive a reference type. Hence I
better by a good java-dev and check for null first and type then. This
implies I have to throw two checked exceptions. But the one calling the
method knows very well that the object is there and is of the right type.
But stand no chance no less. The caller must do a silly try/catch or forward
it upwards which makes even less sense.

Why should it have to throw two checked exceptions? There's are two
perfectly good unchecked exception types specifically for those cases.
The caller will sport code that implies that something may go wrong when it
cannot possibly do so.

I like Anders Hjelsbergs view on this. - Never force a caller to handle
exceptions.

I prefer "force a caller to handle exceptions they might reasonably
recover from, but not others". In my current Java work I'll be using
unchecked exceptions quite a lot - and checked exceptions on occasion,
where I really want to make sure I think about handling them.
Good code have a finally/catch ratio of 10 to 1.
Agreed.


- Nothing wrong if you're writing a general component. But if you're
building an application, you fool the maintainer as to beleive that the
stream may or not work, when it always does. Hence the protection is not
only overkill, but may take the maintainer on a short, but dead end, trail
while debugging.

Why should the maintainer believe that the stream may or may not work,
when both branches of the "if" statement have valid paths? It's not
exactly hard-to-read code, and there's nothing which explicitly throws
an exception there.
- This may be true for C++ and Delphi, as bugs in a release compile often
just yields an access violation and a hexcode address. But for managed code,
most developers just want to find the .cs file and line-number to fix the
darn simple bug.

So you don't see any value in the message or type at all? Bear in mind
that the bug may not be found until after release - at which point
there may not be line numbers available at all... Sure, in an ideal
world all bugs would be found before deployment, but in my experience
that just doesn't happen.
 
M

Michael S

Jon Skeet said:
Why should the maintainer believe that the stream may or may not work,
when both branches of the "if" statement have valid paths? It's not
exactly hard-to-read code, and there's nothing which explicitly throws
an exception there.

It is hard to read if you have to make something work in 15 minutes. =)

So you don't see any value in the message or type at all? Bear in mind
that the bug may not be found until after release - at which point
there may not be line numbers available at all... Sure, in an ideal
world all bugs would be found before deployment, but in my experience
that just doesn't happen.

Maybe this is why we need to fix things in 15 minutes. =)

Anyways, I'll repost the Anders Hjelsberg on checked exceptions.

Part II, the problems with checked exceptions:
http://www.artima.com/intv/handcuffs.html

The index: http://www.artima.com/intv/anders.html

Thanks Jon.

- Michael S
 
S

Sean Hederman

Hazz, in addition to Michaels good points, there's another one to consider:
textBox1.Click += new EventHandler(MyClickHandler);
comboBox1.Click += new EventHandler(MyClickHandler);

The fact that the delegate uses object rather than a strongly typed sender
parameter allows you to be far more flexible in handling standard events. If
they were strongly typed and you wanted to trap the Click event of every
control, you'd have to create an event handler for each type of control you
have on your form. Where it gets really fun is when you don't know that at
design time. Using object completely bypasses all these issues, at the
fairly minor cost of having to cast your sender referenced when you need to
use them.
 
J

Jon Skeet [C# MVP]

Michael S said:
It is hard to read if you have to make something work in 15 minutes. =)

Here's a sample (untested) implementation:

/// <summary>
/// Copies the contents of one stream to another. The source
/// stream should be at the start before the method is called,
/// otherwise the results are undefined.
/// </summary>
/// <param name="source">Stream to copy from</param>
/// <param name="dest">Stream to copy to</param>
static void CopyStream (Stream source, Stream dest)
{
// Optimise for memory streams
MemoryStream ms = source as MemoryStream;
if (ms != null)
{
ms.WriteTo(dest);
}
else // No optimisation - just copy a block at a time
{
byte[] buffer = new byte[8*1024];
int bytesRead;
while ((bytesRead=source.Read(buffer, 0, buffer.Length))>0)
{
dest.Write(buffer, 0, bytesRead);
}
}
}

What would make the maintainer think that either branch is a failure?
You really don't have to be particularly competent to see what's going
on - even without the comments I think it would be pretty clear.
Maybe this is why we need to fix things in 15 minutes. =)

I certainly agree that code needs to be readable - I just don't think
that my code above is hard to read, and the performance improvement can
be significant.
Anyways, I'll repost the Anders Hjelsberg on checked exceptions.

Part II, the problems with checked exceptions:
http://www.artima.com/intv/handcuffs.html

The index: http://www.artima.com/intv/anders.html

I've read it before, and never agreed entirely with it. He has some
good points, and some bad.

In particular, the claim that people are declaring "throws Exception"
in all kinds of Java code is incorrect in my experience - or at least,
things are no better in the C# world where I see plenty of code with

catch (Exception e)
{
....
}

or just

catch
{
....
}

I think checked exceptions have historically been overused, but that
doesn't mean they're a bad thing per se.
 
H

Hazz

Thanks Sean. I get that now. I am going to have to write some test code
to play around with some of these ideas. -hazz
 
B

Bruce Wood

If the eventhandler will never handle anything other than (in this
case)
comboboxes, why do I need to cast to comboboxes?
Is it because sender is of a generic object type? Does the runtime not know
that this is an object of type combobox?
If I am passing by reference rather than by value, doesn't the heap retain
the combobox info?

Be careful here. You are confusing compile-time and run-time concepts.

The explicit cast does two things:

1. It is your "promise" to the compiler that, yes, this thing that is
declared as "object" will be, at run time, a ComboBox, or a type
compatible with ComboBox (such as a child class).

2. Because the compiler doesn't completely trust you, it generates code
to verify that the cast is valid at run-time.

A "cast" absolutely does not _change_ what type of object this is at
run time. Nothing can do that. After you've instantiated a ComboBox it
is a ComboBox forever. What the cast does is gives the compiler the
warm fuzzies: "I, as a programmer, know that the thing that I put in
this "object" reference is a ComboBox. So, just pretend it's a ComboBox
and let's get on with this."

The compiler has no way to know what the variable "sender" will refer
to at run-time, so you have to give it some help.

The "typeof" operator is useful when even you, great programmer that
you are, aren't sure what kind of thing an "object" variable (for
example) refers to. "typeof" generates code to ask, _at run time_, what
kind of thing this is. It is typically then followed by a cast to cast
a more general type (such as "object") to something more specific that
you can work with (such as ComboBox), after you've determined via
"typeof" that it is, indeed, a type compatible with ComboBox.

Take care not to confuse compile time and run time; compile time has,
in many respects, less information available to it, an you often have
to make assurances to the compiler (via things like casts) that you
know what you're doing.
 
M

Michael S

What would make the maintainer think that either branch is a failure?
You really don't have to be particularly competent to see what's going
on - even without the comments I think it would be pretty clear.

Nothing. You optimize for certain subclasses. Great!

I certainly agree that code needs to be readable - I just don't think
that my code above is hard to read, and the performance improvement can
be significant.

The code above is obvious. Ther is no need for simplification nor any
comments in code.
But the code above is not an example of what I'm talking about, like doing
silly stuff like checking for null etc etc.
I've read it before, and never agreed entirely with it. He has some
good points, and some bad.

I can't see the bad points. Not even the the one below. I have read most the
stuff you've written and I'm curious about your thoughts on this...
In particular, the claim that people are declaring "throws Exception"
in all kinds of Java code is incorrect in my experience - or at least,
things are no better in the C# world where I see plenty of code with
*snip*

I think checked exceptions have historically been overused, but that
doesn't mean they're a bad thing per se.

I think the 'as' keyord is great in C#. And in your stream example you use
to show that the object may not be of a certain type and test for it. I
think exceptions are overused in both Java and .NET. My point is still -
Keep it simple and let the driver drive. Hence, a method should not check
its params for null, let the consumer of the method check if a reference
points to an object.

- Michael S
 
M

Michael S

Sean Hederman said:
The fact that the delegate uses object rather than a strongly typed sender
parameter allows you to be far more flexible in handling standard events.
If they were strongly typed and you wanted to trap the Click event of
every control, you'd have to create an event handler for each type of
control you have on your form. Where it gets really fun is when you don't
know that at design time. Using object completely bypasses all these
issues, at the fairly minor cost of having to cast your sender referenced
when you need to use them.

Well said!

- Michael S
 
J

Jon Skeet [C# MVP]

Michael S said:
The code above is obvious. Ther is no need for simplification nor any
comments in code.
But the code above is not an example of what I'm talking about, like doing
silly stuff like checking for null etc etc.

Why is checking for null silly? It makes sure you throw a useful
exception - and that you throw it before you do other things to change
the state. (If possible, a method call which fails should fail without
having done anything.)
I can't see the bad points. Not even the the one below. I have read most the
stuff you've written and I'm curious about your thoughts on this...

I think the 'as' keyord is great in C#. And in your stream example you use
to show that the object may not be of a certain type and test for it. I
think exceptions are overused in both Java and .NET. My point is still -
Keep it simple and let the driver drive. Hence, a method should not check
its params for null, let the consumer of the method check if a reference
points to an object.

That leaves you open for methods which "half work" - and which don't
help you diagnose what you actually did wrong when you get an
exception.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top