Up casting (base to derived) in C#

A

AtariPete

Hey All,

I have a C# question for you regarding up casting (base to derived).

I was wondering about the most elegant way (readable, less code) to
cast from a base type to its derived type. Please consider the
following two classes:

class Base {
private int m_valA;
private int m_valB;

public Base() { }

public Base(int a, int b){
m_valA = a;
m_valB = b;
}

public int ValA
{
get { return m_valA; }
set { m_valA = value; }
}

public int ValB
{
get { return m_valB; }
set { m_valB = value; }
}
}//end class

class Derived : Base
{
public int ValAPlusValB
{
get { return base.ValA + base.ValB; }
}
}//end class

Now consider the scenario where I have an instance of Base (someBase)
and could like to up cast it to a Derived instance (someDerived).
 
B

Bruce Wood

AtariPete said:
Hey All,

I have a C# question for you regarding up casting (base to derived).

I was wondering about the most elegant way (readable, less code) to
cast from a base type to its derived type. Please consider the
following two classes:

class Base {
private int m_valA;
private int m_valB;

public Base() { }

public Base(int a, int b){
m_valA = a;
m_valB = b;
}

public int ValA
{
get { return m_valA; }
set { m_valA = value; }
}

public int ValB
{
get { return m_valB; }
set { m_valB = value; }
}
}//end class

class Derived : Base
{
public int ValAPlusValB
{
get { return base.ValA + base.ValB; }
}
}//end class

Now consider the scenario where I have an instance of Base (someBase)
and could like to up cast it to a Derived instance (someDerived).

I don't understand what you want to know. You cannot cast an instance
to another instance. You cast references, not instances. If you have a
Base reference pointing to an instance of Derived, and you want to cast
it to a Derived reference, there are two ways to do this. Either

Base someBase = new Derived();
Derived someDerived = (Derived)someBase;

or

Base someBase = new Derived();
Derived someDerived = someBase as Derived;

The first way throws an exception if the instance to which "someBase"
refers is not of type Derived or some child type of Derived. The second
way does not throw an exception in this case but instead returns null.

Which one you use depends upon whether, in your application at that
point in the code, the instance must "certainly" be a Derived instance,
or instead the instance "could be" a Derived instance and you want to
handle the case where it isn't.

Is this what you wanted to know?
 
S

Sericinus hunter

AtariPete said:
Hey All,

I have a C# question for you regarding up casting (base to derived).

I was wondering about the most elegant way (readable, less code) to
cast from a base type to its derived type.
[...]

Now consider the scenario where I have an instance of Base (someBase)
and could like to up cast it to a Derived instance (someDerived).

I personally like this:

Derived someDerived = someBase as Derived;
 
A

AtariPete

You cannot cast an instance to another instance.

Bruce,

Thanks for your feedback.

You're correct, I didn't mean "cast one instance to another instance".
I had meant cast an instance of Base to type derived.
Base someBase = new Derived();
Derived someDerived = someBase as Derived;

The issue with this is that i do not control how Base is created. Thus
base is instantiated as follows:
Base someBase = new Base ();
but then if I do the cast
Derived someDerived = someBase as Derived;
someDerived will be null.
 
M

Mark Wilden

I personally like this:

Derived someDerived = someBase as Derived;

I think "as" is frequently misused. In this example, where is the code that
handles when the conversion fails? And if the conversion isn't expected to
fail, why not just use a cast, which will not silently fail if something
goes wrong, but will throw an exception?

///ark
 
B

Bruce Wood

Mark said:
I think "as" is frequently misused. In this example, where is the code that
handles when the conversion fails? And if the conversion isn't expected to
fail, why not just use a cast, which will not silently fail if something
goes wrong, but will throw an exception?

Obviously, there's no error-handling code in a one-line sample. :)

I usually use "as" if I want to treat the "cast failed" case the same
as I would treat a "null value" case. Often it's not a case of an
error, just a case of how you define your methods. You can always
simply state that passing the "wrong" type of instance results in
such-and-so result, rather than throwing an exception.

"Error" is in the eye of the beholder.
 
S

Sericinus hunter

Mark said:
I think "as" is frequently misused. In this example, where is the code that
handles when the conversion fails? And if the conversion isn't expected to
fail, why not just use a cast, which will not silently fail if something
goes wrong, but will throw an exception?

The code that handles the conversion failure is on the next line. :)
 
B

Bruce Wood

AtariPete said:
Bruce,

Thanks for your feedback.

You're correct, I didn't mean "cast one instance to another instance".
I had meant cast an instance of Base to type derived.


The issue with this is that i do not control how Base is created. Thus
base is instantiated as follows:
Base someBase = new Base ();
but then if I do the cast
Derived someDerived = someBase as Derived;
someDerived will be null.

Yes. Given your sample code, someDerived will always be null. If the
CLR allowed any other result then it would break type safety. This

Derived someDerived = new Base();

is always illegal and must always fail, or the whole type safety thing
falls apart.
 
M

Mark Wilden

Obviously, there's no error-handling code in a one-line sample. :)

My point was that that code is usually all there is. People often don't seem
to realize that "as" -requires- error-handling code, whereas casts don't.
I usually use "as" if I want to treat the "cast failed" case the same
as I would treat a "null value" case.

I'm trying to think of why on earth anyone would want to treat them the
same, but I can't.
Often it's not a case of an
error, just a case of how you define your methods. You can always
simply state that passing the "wrong" type of instance results in
such-and-so result, rather than throwing an exception.

And that is way over my head.

///ark
 
B

Bruce Wood

Mark said:
My point was that that code is usually all there is. People often don't seem
to realize that "as" -requires- error-handling code, whereas casts don't.


I'm trying to think of why on earth anyone would want to treat them the
same, but I can't.

Here's an example, both of this and of what I was talking about after
that:

public override bool Equals(Object obj)
{
MyType other = obj as MyType;
return other != null && other._id == this._id;
}

If I pass some other type to Equals, should it throw an
ArgumentException, or return false? If I pass null to Equals, should it
throw an ArgumentNullException, or return false? It all depends upon
your definition of what "Equals" means, and how you want to treat edge
cases. You may choose to make Equals very cranky and have it throw
exceptions, or simply say, "No... that is not equal to this."
 
M

Mark Wilden

public override bool Equals(Object obj)
{
MyType other = obj as MyType;
return other != null && other._id == this._id;
}

I see what you mean - that makes sense.

///ark
 
J

Jon Skeet [C# MVP]

Bruce Wood said:
Here's an example, both of this and of what I was talking about after
that:

public override bool Equals(Object obj)
{
MyType other = obj as MyType;
return other != null && other._id == this._id;
}

If I pass some other type to Equals, should it throw an
ArgumentException, or return false? If I pass null to Equals, should it
throw an ArgumentNullException, or return false? It all depends upon
your definition of what "Equals" means, and how you want to treat edge
cases. You may choose to make Equals very cranky and have it throw
exceptions, or simply say, "No... that is not equal to this."

In this case it's actually less of an open queston than it might be -
the MSDN documentation states that it should return false. I see your
point though, and in other situations where the documentation is less
clear, it's a much more difficult decision.
 
B

Bruce Wood

Jon said:
In this case it's actually less of an open queston than it might be -
the MSDN documentation states that it should return false. I see your
point though, and in other situations where the documentation is less
clear, it's a much more difficult decision.

For my money, this is one of the things that makes error handling such
a bear. If you make your methods very strict and cranky, so that they
throw an exception for the slightest offense, you end up with client
code having to do lots of checking before passing arguments to this
cranky method.

If, on the other hand, you let things like wrong types or nulls slide
by returning some sort of default value, you run the risk, as Mark
pointed out, of having errors go undetected.

Often when you're writing a method you don't know enough about how it
will be used to know whether a given situation should be considered an
error or not. Making the wrong decision can cause problems down the
road... not intractable problems, but annoying ones.
 
A

AtariPete

so where does this leave us. how might I up cast then the base class
isn't instantiated with the derived type?
 
J

Jon Skeet [C# MVP]

AtariPete said:
so where does this leave us. how might I up cast then the base class
isn't instantiated with the derived type?

Firstly, just to correct your terminology, I believe you're actually
talking about *down*casting. Upcasting is the (almost always
unnecessary) casting from the derived class to the base class.

Now, as for downcasting when the instance in question *isn't* an
instance of the derived class - you can't. The cast won't work (which
is a good thing really - otherwise you'd have to "guess" what the
values of extra fields would be, for starters). What you *could* do is
write a constructor in the derived class which takes a reference to an
instance of the base class, and creates a new instance of the derived
class with mostly the same field values, etc.
 
M

Mark Wilden

Upcasting is the (almost always
unnecessary) casting from the derived class to the base class.

How "almost"? (I have the unpleasant feeling that I'm about to learn
something.)

///ark
 
J

Jon Skeet [C# MVP]

Mark Wilden said:
How "almost"? (I have the unpleasant feeling that I'm about to learn
something.)

You sometimes need to cast in order to pick the right overload. For
instance:

using System;

class Test
{
static void Main()
{
string x = "hello";
Foo(x);
Foo((object)x);
}

static void Foo(string x)
{
Console.WriteLine ("Foo(string)");
}

static void Foo(object o)
{
Console.WriteLine ("Foo(object)");
}
}
 
S

Sericinus hunter

Mark said:
How "almost"? (I have the unpleasant feeling that I'm about to learn
something.)

To my understanding, using this construct
((BaseClass)instanceOfDerivedClass).Method() you will call base class
implementation of Method(), given it is not virtual and overridden
in the derived class.
 
T

Tigger

Dont forget that you can also use the is keyword:

if (obj is MyType)
{
MyType myObject = (MyType)obj;
// do my thing
}

I also believe casting can return null (if supplied with null) so error
checking is also needed if you cast (except above where you pre-check
its safe)

Tony
 
S

Shawn Wildermuth (C# MVP)

Hello Tigger,

Almost always the better pattern is to try the cast with the "as" operator:

MyType myObject = obj as MyType;
if (myObject != null)
{
// do my thing
}

This is more efficient (and in my opinion is more direct to read).

Thanks,
Shawn Wildermuth
Speaker, Author and C# MVP
http://adoguy.com
 

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