At times there are going to be objects that are of different types, but share some common functionality. Generally when this happens we add an interface that contains those commonalities and then have those classes implement the interface. This allows us to treat those objects as the same types through polymorphism.
Let's say the Custodian of the Zoo wants to go around to everything they can clean and clean it. We have two things in our Zoo (Booth and Restroom) that are cleanable things. The custodian already has a list of restrooms that we can add a Restroom object to just fine.
As we would expect, though, if we tried to add a type of Booth to the list we would get an error because the AddRestroom method only takes Restroom types.
So let's change what the AddRestroom method can take as an argument. Instead of Restroom let's have it take a type of ICleanable. This basically says, "I don't care what you are as long as you're a cleanable." Let's rename the method while we're at it to something a little more generic.
We have the structure of the method in place but still have an error. If we look at the MainWindow, though, we can see that it is just fine passing in both the Restroom type and a Booth type because they are both ICleanable.
Now all we have to do is change the list so that it can only contain ICleanable types. Once we do that, the cleanable in the AddCleanable method can be added just fine.
Now we can see that we have a list of many specific types as their more generic types.
And the custodian can loop through the list of cleanables and call methods related to ICleanables.
While our list of ICleanable types does what we want it to do if we only want to do "cleanable" things, what if we want to do something that has been taken away because we've casted the object to an interface? We will cast it back to what it was.
Let's say the Booth has a method called DustCounter that isn't part of the ICleanable interface? If the Booth is an ICleanable when looping through the list, that method will never be available to us. So we need to cast it. The first thing we are going to do is check if the object is a Booth.
Then, if it is we want to cast is as a Booth.
Now that the b object is a Booth, we have access to the members of the Booth class.