Resolved Cast base object to an inherited object

bondra

Well-known member
Joined
Oct 24, 2020
Messages
77
Programming Experience
Beginner
I'm trying to cast an object that's being passed into a method to one of its inherited classes/objects.
Since I want to prevent duplicated code as far as possible. Last example is the working one and maybe the best solution even though it has duplicated text blocks?

What's your thoughts on this in general? How would you have done it?

Example 1 - Not working one but the prefered one
Using this would leave me only with one block of texts i.e. "The ... is not playing with..."
toy is never casted to ball (as I was hoping and expected) however. Thus let me access the property Color from Ball.

C#:
        public void InitPlay(Toy toy)
        {
            if (toy is Ball ball)
            {
                toy  = (Ball)toy; // At this point I was expecting toy to be casted to the Ball object...
            }
            else if (toy is Bone bone)
            {
                toy  = (Bone)toy; // At this point I was expecting toy to be casted to the Bone object...
            }

            Console.WriteLine($"\n - Press enter to start playing with the {toy}");
            Console.ReadLine();

            Console.WriteLine(" --------------------------------------------------------");
            // ... and thus be able to reach Color in the Ball object using toy.Color. With no luck.
            Console.WriteLine($" The {TypeOfAnimal}{Name} is now playing with the {toy.Color} {toy} ");
            Console.WriteLine(" - Press enter to finish playing ");
            Console.WriteLine(" --------------------------------------------------------");
        }

Example 2 - Working one but with duplicated text blocks

C#:
        public void InitPlay(Toy toy)
        {
            Console.WriteLine($"\n - Press enter to start playing with the {toy}");
            Console.ReadLine();

            if (toy is Ball ball)
            {
// This forces me to have more or less duplicated blocks of text just to reach properties from each inherited object.
                Console.WriteLine(" --------------------------------------------------------");
                Console.WriteLine($" The {TypeOfAnimal}{Name} is now playing with the {ball.Color} {toy} ");
                Console.WriteLine(" - Press enter to finish playing ");
                Console.WriteLine(" --------------------------------------------------------");
            }
            if (toy is Bone bone)
            {
                Console.WriteLine(" --------------------------------------------------------");
                Console.WriteLine($" The {TypeOfAnimal}{Name} is now playing with the {bone.Size} {toy} ");
                Console.WriteLine(" - Press enter to finish playing ");
                Console.WriteLine(" --------------------------------------------------------");
            }
        }
 
Time to take advantage of polymorphism.
 
Think about what that first example is doing. The toy parameter is declared as type Toy. What exactly do you think this does:
C#:
toy  = (Ball)toy;
It doesn't matter what you do on the righthand side because you assign the result to the toy variable. If toy is declared as type Toy, how could you possibly get anything other than a Toy reference from it? The actual object was already type Ball so you're not changing the type of the object and you're not changing the type of the variable, so you're doing nothing at all. The cast IS made, but you basically cast it back to the base type again immediately.
 
I'm trying to cast an object that's being passed into a method to one of its inherited classes/objects.
The important question is WHY. You're telling us what you're trying to do and you're showing us how you're trying to do it but you're not explaining what problem you think you're solving by doing this. It is almost certainly misguided. The whole point is that you DON'T cast the base reference. You declare the members in the base class as abstract or as virtual with a default implementation and then you override them in the derived types. That way, you can just access the member(s) via the base reference and it will invoke the derived implementation automatically. That is the polymorphism that @Skydiver was talking about and it's pretty much the whole point of inheritance. If you need to invoke members that aren't common then you almost certainly shouldn't be passing a reference of the base type in the first place.
 
To follow on to @jmcilhinney post #3 above, C# is not like Groovy where the types of variables are automatically dynamically typed. (You can use the dynamic keyword to get dynamic types in C#, but personally I find that this actually makes code harder to understand.)
 
You can use the dynamic keyword to get dynamic types in C#, but personally I find that this actually makes code harder to understand.
It's pretty rare that dynamic should be used. It's the sort of thing that some people might use to hide problems rather than solve them. It can be used to provide late-binding for things like Office Automation, like Option Strict Off in VB, and it serves a purpose for things like the ViewBag property in MVC controllers and views. Personally though, I've never had cause to declare something dynamic myself.
 
The important question is WHY. You're telling us what you're trying to do and you're showing us how you're trying to do it but you're not explaining what problem you think you're solving by doing this. It is almost certainly misguided. The whole point is that you DON'T cast the base reference. You declare the members in the base class as abstract or as virtual with a default implementation and then you override them in the derived types. That way, you can just access the member(s) via the base reference and it will invoke the derived implementation automatically. That is the polymorphism that @Skydiver was talking about and it's pretty much the whole point of inheritance. If you need to invoke members that aren't common then you almost certainly shouldn't be passing a reference of the base type in the first place.
I actually did this but used abstract. Really don't know why I didn't tested virtual as well. It's those two we've been taught in school.
Virtual however worked just fine! A one second fix was all that was needed! (y)
 
There's no need to cast if the member is declared abstract or virtual. In case you're not clear on the distinction, you would use abstract if you wanted to declare the member in the base class but only provide an implementation in each base class, while you would use virtual if you wanted to provide a default implementation in the base class that may or may not be overridden in each derived class. Note that, if you declare a member abstract, you must declare the type abstract as well, which means that you can never create an instance of that class directly. If it exists solely to be a base for other classes anyway, that's not an issue. Here's an example of an abstract method:
C#:
class Program
{
    static void Main()
    {
        var fruits = new Fruit[] {new Apple(), new Orange()};

        foreach (var fruit in fruits)
        {
            DisplayName(fruit);
        }

        Console.ReadLine();
    }

    private static void DisplayName(Fruit fruit)
    {
        Console.WriteLine(fruit.GetName());
    }
}

public abstract class Fruit
{
    public abstract string GetName();
}

public class Apple : Fruit
{
    public override string GetName()
    {
        return "Apple";
    }
}

public class Orange : Fruit
{
    public override string GetName()
    {
        return "Orange";
    }
}
In this case, both Apple and Orange are required to provide their own implementation of GetName. The output of that code is this:
Apple
Orange
Here's an example of a virtual method:
C#:
class Program
{
    static void Main()
    {
        var fruits = new Fruit[] {new Apple(), new Orange()};

        foreach (var fruit in fruits)
        {
            DisplayName(fruit);
        }

        Console.ReadLine();
    }

    private static void DisplayName(Fruit fruit)
    {
        Console.WriteLine(fruit.GetName());
    }
}

public class Fruit
{
    public virtual string GetName()
    {
        return "Unnamed Fruit";
    }
}

public class Apple : Fruit
{
    public override string GetName()
    {
        return "Apple";
    }
}

public class Orange : Fruit
{
}
In this case, Apple and Orange can provide their own implementation but they don't have to. If they do, calling that method will invoke that implementation, otherwise the default implementation in the base class will be invoked. The output of that code is this:
Apple
Unnamed Fruit
 
Back
Top Bottom