tags:

views:

355

answers:

11

Given that I have an instance of Fruit with some properties set, and I want to get those properties into a new Pear instance (because this particular Fruit happens to have the qualities of a pear), what's the best way to achieve this effect?

For example, what we can't do is simply cast a Fruit to a Pear, because not all Fruits are Pears:

public static class PearGenerator {
    public static Pear CreatePear () {

        // Make a new generic fruit.
        Fruit genericFruit = new Fruit();

        // Upcast it to a pear. (Throws exception: Can't cast a Fruit to a Pear.)
        Pear pear = (Pear)genericFruit;

        // Return freshly grown pear.
        return ( pear );
    }
}

public class Fruit {
    // some code
}

public class Pear : Fruit {

    public void PutInPie () {
        // some code
    }

}

Thanks!

Update:

I don't control the "new Fruit()" code. My starting point is that I've got a Fruit to work with. I need to get that Fruit into a new Pear somehow. Maybe copy all the properties one by one?

+15  A: 

Because the Fruit you've created isn't a Pear!


Edit: If you already have a Fruit and need to create a Pear from it then yes, you have no choice but to copy all the properties to a new Pear object. This should ideally be done inside a Pear constructor that you create especially for that purpose.

Evgeny
yeah, think about it as "All pears are fruits (thats why you can cast from pear to fruit) but not all fruits are pears (so you cant force it to be a pear)"
Francisco Noriega
+4  A: 

A Pear is a Fruit.

Fruit is not necessarily a Pear.

KevinH
+13  A: 

It's not a pear. Try replacing your line

Fruit genericFruit = new Fruit();

with:

Fruit genericFruit = new Pear();
Alun Harford
This is key. Understand this and when to use it, and you've mastered an important OO concept.
Bob Kaufman
+5  A: 

The downcast fails, because the instance created is a Fruit, to make it a Pear, change the code to

    // Make a Pear - it looks like a fruit, tastes like a fruit,
    // and quacks like a fruit. It must be a fruit.
    Fruit genericFruit = new Pear();

    // Downcast it to a pear. 
    Pear pear = (Pear)genericFruit;

Down-casting looks at the actual type, not the declared type - but you don't know what the actual type is (unless you test using is/as). This is why it's a little dangerous and most people try to avoid downcasting where possible.

EDIT: To make a fruit into a pear, you can create a new Pear yourself and initialize it as best you can. Some of the properites common to all fruit may be copied, from the fruit to the pear. But it may also be like trying to put a square peg into a round hole, mixing your metaphors and ending up with fruit puree.

mdma
+2  A: 

If Pear defined a load of new stuff.. and you created Fruit.

If you upcast Fruit to Pear what should all the extra stuff in Pear be set to?

It would all be undefined stuff. Hence why its not allowed!

Mongus Pong
+2  A: 

When you're casting you're not actually changing any data, just the "label" if you will. If you have a Pear that was cast to a Fruit, then it can be cast back into a Pear, but if it was never a Pear to begin with, casting won't convert it into a Pear.

Davy8
A: 

Like Evgeny said what are doing is not legal because it is not typesafe. Downcasting a super type to a derived type if not allowed.

There are various ways to solve your problem, all depending on your situation

Generics, dynamic ( C# 4.0 only), Abstract classes, Interfaces.

Foovanadil
+3  A: 

If you're not responsible for Fruit but are the author of Pear, then maybe a different design would help:

It may be better to change your Pear class to more of a FruitWrapper class. This class would hold a reference to a Fruit instead of being a more specific kind of Fruit. It can have its own functionality (the reason you don't want to use Fruit in the first place), and pass on fruit-type functionality to the Fruit it's got inside. If it needs to work with library code that expects a Fruit, just pass the one it's holding on to...

grossvogel
+1  A: 

Is it absolutely necessary to inherit?

... I think the Pear -> fruit example is making this tough... this is an example right?

What about creating your Pear class like:

public class Pear { 

    public Fruit {get; set;}

    public void Pear(add pear properties, Fruit fruit)
    {
         // assign pear properties
         Fruit = fruit;
    }

    public void PutInPie () { 
        // some code 
    } 

}

This may not be ideal but its an idea.

Good luck,

Patrick

Patrick
A: 

You could create a new constructor for Pear that accepts an instance of Fruit.

A: 

This example reminds me of the one in this article. Take a look there at an interesting discussion of inheritance vs composition. Think about the fragile base class problem. To map from one object to the other, you can use AutoMapper.

Jordão