Being able to substitute objects at runtime is the basis of the Liskov substitution principle. In OOP, if a class inherits from a base class or implements an interface, then it can be referenced as an object of the base class or interface. This is easier to describe with a simple example.
We'll define an interface for an animal and implement two animals, Cat and Dog, as follows:
interface IAnimal
{
string MakeNoise();
}
class Dog : IAnimal
{
public string MakeNoise()
{
return "Woof";
}
}
class Cat : IAnimal
{
public string MakeNoise()
{
return "Meouw";
}
}
Then we can refer to the Cat and Dog as an animal as follows:
var animals = new List<IAnimal> { new Cat(), new Dog() };
foreach(var animal in animals)
{
Console.Write(animal.MakeNoise());
}