There is a behavior in C# I really do not understand:
class Animal {
public string species = "animal";
public void Introduce() {
Console.WriteLine(species);
}
}
class Cat: Animal {
new public string species = "cat";
// public void Introduce() {Console.WriteLine(species);}
}
class Program
{
static void Main(string[] args)
{
var cat = new Cat();
cat.Introduce();
}
}
This piece of code, when executed, outputs >>> animal.
For me, since Cat inherits Animal, calling cat.Introduce should call Animal.Introduce "in the scope of the cat instance". ie I don't understand why the program picks the species field of Animal and not the one of Cat...
I know I could use workarounds, but I believe I'm missing some point about c# design, can someone explain this behavior?
Thanks
I don't understand why the program picks the species field of Animal and not the one of Cat...
Because the new modifier hides the inherited species member... but only inside the Cat instance. You call the method on the base class, which only knows its own species member.
If you give your Cat class an IntroduceCat() method where you print its species and you call it, you'll see the "cat" string being printed.
If you want to override the member in a derived class, you must mark the member as virtual in the base class and override it in the derived class. But you can't do that to fields, so you'll have to make it a property.
But you probably just want to assign a different value, and you can do so in your constructor.
Related
Can someone explain the difference between an override and just a normal method, and when an override should be used over the latter?
Every tutorial I have found uses words like "Polymorphism" and "Derived Classes" rather than just explain their application and when they should be used.
I am using C# in particular but an understanding of overrides as a concept would be very helpful.
Thanks for any input on the subject.
Simply put, overrides are for when you want to change the behavior of a method in a derived class. For example, say you had an Animal.Speak() method:
class Animal
{
public virtual void Speak()
{
Console.WriteLine("The animal makes random animal noises.");
}
}
Now, if you had a specific type of animal, you'd want to override that Speak() method to make noises that that type of animal would make:
class Dog : Animal
{
public override void Speak()
{
Console.WriteLine("The dog barks.");
}
}
Now if you make a Dog object and tell it to speak, it will bark. Now let's consider if you had a Cat class but didn't override the Speak() method:
class Cat : Animal
{
}
If you had this code:
Animal dog = new Dog();
Animal cat = new Cat();
dog.Speak();
cat.Speak();
You'd see this:
The dog barks.
The animal makes random animal noises.
For example, if there is an predefined class which has a method "ABC" and you want to change its behavior. In that case you have to write the keyword override before the method ABC that you want to change from its default to what you really want to have. Simple words use override when you have to change already existing method. Do not use override when you are creating a new method of any object which already does not exists.
Overriding occurs when you make a method/function/subroutine that has the same name as another function, but has different functionality. One prominent example is the Equals method. This method can be overridden for a custom object to return your concept of equality. For example, if you have a Person object and decide that 2 Persons are equal when they have the same name, you could override the existing Equals method to return whether or not 2 Persons have the same name. Good luck!
What do you mean by "overriden" method?
There are two options:
Override virtual methods in subclasses. Here "method overriding" is a part of polymorphism - one of the concept of object-oriented programming.
For instance, here you have a base class A with some virtual methods:
public class A
{
public void Method1() {}
public virtual void Method2() {}
public virtual void Method3() {}
}
If you create class B, which is derived from A you will have an opportunity to override virtual methods in such case:
public class B : A
{
public override void Method2() {}
public override void Method3() {}
}
In such way you change your base functionality from class A by your new functionality from class B.
So, when you call method from instance of class B , you will get functionality from overriden method in class B:
B instanceB = new B();
instanceB.Method2();
Override method signature. Here you are able to have multiple methods with same name, but with different signatures.
For example, you have such class with 3 methods, which have one name TestMethod, but there are different signatures (different input and output parameter types):
public class TestClass
{
public void TestMethod() {}
public int TestMethod(int value) {}
public string TestMethod(int value) {}
}
Given
public class Animal
{
public Animal()
{
Console.WriteLine("Animal constructor called");
}
public virtual void Speak()
{
Console.WriteLine("animal speaks");
}
}
public class Dog: Animal
{
public Dog()
{
Console.WriteLine("Dog constructor called");
this.Speak();
}
public override void Speak()
{
Console.WriteLine("dog speaks");
base.Speak();
}
}
this.Speak() calls Dog.Speak(). Remove Speak() from dog and suddenly this.Speak() calls Animal.Speak(). Why does this behave this way? In other words, why does this mean base or this?
To me, an explicit call to base.Speak() makes more sense. Especially when speak is not virtual, surprisingly Speak() is still called when virtual is removed. I understand IS-A relationships from an OO sense, but I can't wrap my head around this specific problem in C#. This gets especially annoying when people write God class UI's (practically every business does). I'm looking for "Speak()" inside "this" when I should be looking at "base".
Subclases automatically inherit behavior from their base classes. If you don't do anything other than inherit Dog from Animal then this.Speak() and base.Speak() both reference the version of Speak() that was implemented in Animal.
Where special things start happening is if Dog overrides Speak(). This is not possible unless Speak() is virtual. (The virtual keyword doesn't control inheritance, it controlls overriding.)
Only when Dog overrides Speak() does base.Speak() do something special: In that case, calling Speak() (or this.Speak()) will execute Dog's implementation, because it overrides Animal's implementation. This is where base becomes useful: it allows you to get around this behavior by specifying that you want to execute the base class's implementation rather than the override.
A common use of this style is in constructors. For example:
public class Animal
{
private readonly string _name;
public Animal() : this("Animal") { }
protected Animal(string name) { _name = name; }
public void Speak() { Console.WriteLine(_name + " speaks"); }
}
public class NamedAnimal : Animal
{
public NamedAnimal(name) : base(name) { }
}
// usage:
(new Animal()).Speak(); // prints "Animal speaks"
(new NamedAnimal("Dog")).Speak(); // prints "Dog speaks"
In this example, NamedAnimal doesn't have access to the _name field, but it is still able to set it indirectly by calling the base class's constructor. But the base class's signature is the same as one in the base class, so it has to be specified using base.
With non-constructors it's also useful to get at behavior that's not otherwise accessible. For example, if Animal.Speak were virtual then we could use an override to tack behavior onto it rather than simply replacing it:
public class NamedAnimal : Animal
{
public NamedAnimal(name) : base(name) { }
public override Speak()
{
Console.Write("The animal named ");
base.Speak();
}
}
// usage:
(new NamedAnimal("Dog")).Speak(); // Writes "The animal named Dog speaks"
Its not that. Its that if there is a speak method within dog, then it is an override of the base method. If it isn't there, then calling dogInstance.Speak will look for the Speak() method in any of Dog's base classes.
This is one of the very fundamental points of OO. If you don't provide an override, then the parent method is used.
Also, even if you remove virtual, Dog.Speak is called because you're not accessing this polymorphically.
this means this and nothing else.
Just in your first example you have an override for Speak(..) function, so this call that one.
In second case, istead, there is no any override, so it "climbs" on derivation tree and pick the first suitable function. In your case that one is Speak(..) of the Animal.
VB.Net has the MyClass keyword to do just that (as opposed to the My keyword, which is the equivalent of this in C#). Unfortunately, there is no MyClass equivalent keyword in C#.
Got a task to make a program that registers animals and the object is to get familiar with inheritance, polymorphism and so on.
One thing that pussles me is no matter how much I read about it just seems pointless.
I create my main class which is animal with some generic fields that apply to all animals lets say name, age and species.
So far so good all animals has this info but every animal has a unique field aswell so ill create my cat as public class cat : animal and give the cat the field teeth for example.
Now I want to make a new animal which is a cat, im taking data from several listboxes so I would need a constructor that takes those parameters and this is what I dont get, do I have to declare them in every child class aswell?
I know that my animal should have 3 parameters from the animal class plus another from the cat class so the new cat should accept (name, age, species, teeth) but it seems that I have to tell the constructor in the cat class to accept all of these and theres my question, what purpose does the animal class serve? If I still need to write the code in all subclasses why have the base class? Probably me not getting it but the more I read the more confused I become.
Like Sergey said, its not only about constructors. It saves you having to initialize the same fields over and over. For example,
Without inheritance
class Cat
{
float height;
float weight;
float energy;
string breed;
int somethingSpecificToCat;
public Cat()
{
//your constructor. initialize all fields
}
public Eat()
{
energy++;
weight++;
}
public Attack()
{
energy--;
weight--;
}
}
class Dog
{
float height;
float weight;
float energy;
string breed;
int somethingSpecificToDog;
public Dog()
{
//your constructor. initialize all fields
}
public Eat()
{
energy++;
weight++;
}
public Attack()
{
energy--;
weight--;
}
}
With Inheritance
Everything common to animals gets moved to the base class. This way, when you want to setup a new animal, you don't need to type it all out again.
abstract class Animal
{
float height;
float weight;
float energy;
string breed;
public Eat()
{
energy++;
weight++;
}
public Attack()
{
energy--;
weight--;
}
}
class Cat : Animal
{
int somethingSpecificToCat;
public Cat()
{
//your constructor. initialize all fields
}
}
class Dog : Animal
{
int somethingSpecificToDog;
public Dog()
{
//your constructor. initialize all fields
}
}
Another advantage is, if you want to tag every animal with a unique ID, you don't need to include that in each constructor and keep a global variable of the last ID used. You can easily do that in the Animal constructor since it will be invoked everytime the a derived class is instantiated.
Example
abstract class Animal
{
static int sID = 0;
float height;
float weight;
int id;
public Animal()
{
id = ++sID;
}
}
Now when you do;
Dog lassie = new Dog(); //gets ID = 1
Cat garfield = new Cat(); // gets ID = 2
If you want a list of all Animals in your 'farm',
without inheritance
List<Cat> cats = new List<Cat>(); //list of all cats
List<Dog> dogs = new List<Dog>(); //list of all dogs
...etc
With inheritance
List<Animal> animals = new List<Animal>(); //maintain a single list with all animals
animals.Add(lassie as Animal);
animals.Add(garfield as Animal);
This way, if you want to see if you have an animal called Pluto, you just need to iterate over a single list (animals) rather than multiple lists (Cats, Dogs, Pigs etc.)
EDIT in response to your comment
You don't need to instantiate Animal. You simply create an object of whichever Animal you want to. In fact, since an Animal will never be a generic Animal, you can create Animal as an abstract class.
abstract class Animal
{
float height;
float weight;
float energy;
string breed;
public Eat()
{
energy++;
weight++;
}
public Attack()
{
energy--;
weight--;
}
}
class Cat : Animal
{
int somethingSpecificToCat;
public Cat()
{
//your constructor. initialize all fields
}
}
class Dog : Animal
{
int somethingSpecificToDog;
public Dog()
{
//your constructor. initialize all fields
}
}
Cat garfield = new Cat();
garfield.height = 24.5;
garfield.weight = 999; //he's a fat cat
//as you can see, you just instantiate the object garfield
//and instantly have access to all members of Animal
Animal jerry = new Animal(); //throws error
//you cannot create an object of type Animal
//since Animal is an abstract class. In this example
//the right way would be to create a class Mouse deriving from animal and then doing
Mouse jerry = new Mouse();
Edit to your comment
If you store it in a list of Animals, you still have access to all fields. You just have to cast it back to its original type.
List<Animal> animals = new List<Animal>();
animals.Add(garfield as Animal);
animals.Add(lassie as Animal);
//if you do not cast, you cannot access fields that were specific to the derived class.
Console.WriteLine(animals[0].height); //this is valid. Prints Garfield's height
Console.WriteLine(animals[0].somethingSpecificToCat); //invalid since you haven't casted
Console.WriteLine((animals[0] as Cat).somethingSpecificToCat); //now it is valid
//if you want to do it in a loop
foreach(Animal animal in animals)
{
//GetType() returns the derived class that the particular animal was casted FROM earlier
if(animal is Cat)
{
//the animal is a cat
Cat garfield = animal as Cat;
garfield.height;
garfield.somethingSpecificToCat;
}
else if (animal is Dog)
{
//animal is a dog
Dog lassie = animal as Dog;
lassie.height;
lassie.somethingSpecificToDog;
}
}
You probably need to bare in mind that the example you are working through is extremely simple. If you need some complex method to determine one of the base class values you wouldn't want to be writing/replicating this in multiple classes as this would become tedious and make maintenance of the code a nightmare, in these types of situations the declaration of a few params in a constructor becomes trivial.
The benefit is that you dont have to declare the name age species in every type of animal. You get them pre-made for you. Another great point that inheritance lets you do is. Lets say you want to have an array of animals. So you type something like . Arraylist arr = etc etc...
but this will only hold cat type objects. So instead you can do something like Arraylist and this will hold all types of animals, cats and dogs. Basically a variable of a base class can point to a variable of a derived class. This comes real handy in most scenarios, as things get complicated.
You need to tell the contructor to take the arguments (if you wan't to require them), but you do not need to implement the properties again:
public class Animal
{
public string Name { get; set; }
public Animal(string Name)
{
Name = name;
}
}
public class Cat : Animal
{
public int Teeth { get; set; }
public Cat(string name, int teeth)
{
Name = name; //<-- got from base
Teeth = teeth; //<-- defined localy
}
//or do this
public Cat(string name, int teeth) : base(name)
{
Teeth = teeth;
}
}
You can also do the following:
Cat cat = new Cat("cat", 12);
Animal kitty = cat as Animal;
Which makes sense e.g. if you want a list like List<Animal> you can add a Cat-instance:
List<Animal> animals = new List<Animal>();
animals.Add(new Animal("Coco"));
animals.Add(cat);
foreach(Animal animal in animals)
{
Console.WriteLine(String.Format("Name: {0}", animal.Name));
if(animal is Cat)
{
Console.WriteLine(String.Format("{0} is a Cat with {1} teeth.", animal.Name
(animal as Cat).Teeth));
}
Console.WriteLine("============");
}
which will output:
Name: Coco
============
Name: cat
cat is a Cat with 12 teeth.
============
Inheritance is not about constructors only. For example, in your base class Animal you can declare method Eat(something) or Grow() which will be equal for all the successors.
BTW, no problem is in calling default Cat() constructor with just three parameters (so calling the base Animal constructor) and then specifying teeth by setting appropriate field or property.
I don't know if the following information will be of any use for you but I thought it'd be worth mentioning as a use of inheritance.
One of the many uses of inheritance, or to be more specific, a super class is that you can put them in the same collection:
List<Animal> animals = new List<Animal>();
animals.Add(new Cat());
animals.Add(new Dog());
etc. etc.
Don't forget you can just pass constructor params to the base contructor too. You don't have to init them all in every derived class.
eg (stealing chrfin's code):
public class Animal
{
public string Name { get; set; }
}
public class Cat : Animal
{
public int Teeth { get; set; }
public Cat(string name, int teeth) : Base(name) //pass name to base constructor
{
Teeth = teeth;
}
}
You're totally overthinking this.
what purpose does the animal class serve?
Your scenario is really, really simple. Try to think of it this way: the more common the feature is, the higher in the hierarchy it should be placed. Why? Simply to avoid duplication and redundancy. Imagine having few additional classes: dog, horse and frog. Since cat, dog and horse are mammals, you could as well create a class mammal defining shared mammals' features. Why? For example to avoid writing the same constructors, fields, methods for the similar species. In your case try to think of your animal class as of a repository of features common to all animals.
Yes you will have to create the constructors, but that doesn't make inheritance pointless, although it is actually a good design practice to prefer composition over inheritance, that is generally (not always) it is better to have a cat that HAS-A animal property than a cat that IS-A animal.
Going back to inheritance, when it really pays off, since there are some attributes that all your animals will have think maybe, legs, ears, head, and by using inheritance you will not have to declare those properties in every class you create.
Also with inheritance you can use polymorphism, say you have this class (pseudo-code)
public abstract class Animal()
{
//Some atributes
//Methods
makeSound();
}
then you have
public class Cat extends Animal
{
makeSound()
{
System.out.println("meow");
}
}
Then say you extend Animal for dog also:
public class Dog extends Animal
{
makeSound()
{
System.out.println("woof")
}
}
Now say you have an array declared like this:
List<Animal> animals = new ArrayList<Animal>();
animals.add(cat);
animals.add(dog);
Then say you want each animal to make his sound then you can use polymorphism, and that will make each implementation call its makeSound method:
for (Animals animal : animals)
{
animal.makeSound();
}
And that will print for the cat
"meow"
and for the dog
"woof"
Inheritance allows you to write code that is shared between classes so that you put common functionality/data within a base class and have other classes derive from it. To use your example:
class Animal
{
public string Name { get; set; }
public Animal(string name)
{
Name = name;
}
}
class Cat : Animal
{
// Put cat-only properties here...
public Cat(string name) : base(name)
{
// Set cat-specific properties here...
}
}
You don't even need to supply the same amount of parameters to each class constructor - if a cat doesn't have a name (for a contrived example) just create a Cat constructor with no parameters and pass in something suitable to the base constructor. This allows you to control how all the animal classes are setup.
You are getting confused because you are thinking only about constructors. The fact is as explained in msdn, "Constructors and Destructors are not inherited". So when you inherit you a class the base class constructors do not apply to derived class. Derived class has to mention its own set of construtor/destructor. To understand why this is so you might look here: Why are constructors not inherited?.
Now coming to your question, Yes you have to add a constructor in your cat class to accept all the four parameters. But you need not have to implement those 3 fields again in your cat class. All public protected and internal fields and methods of your animal class are still available to your cat class and you do not have to reimplement them in your derived class. This is how your base class is serving your derived class.
I understand what a virtual function is. But what I don't get is how do they work internally?
class Animal
{
virtual string Eat()
{
return #"Eat undefined";
}
}
class Human : Animal
{
override string Eat()
{
return #"Eat like a Human";
}
}
class Dog : Animal
{
new string Eat()
{
return #"Eat like a Dog";
}
}
static void Main()
{
Animal _animal = new Human();
Console.WriteLine(_animal.Eat());
_animal = new Dog();
Console.WriteLine(_animal.Eat());
}
Output for the above gives:
Eat like a Human
Eat undefined
In the above code _animal is of type Animal which references a Human object or Dog object.
What does this mean? I understand in the memory _animal contains an address which will point to Human or Dog object. How does it decide which function to invoke. In the first case I override and hence child's implementation is called, but in second case I use new and hence the parent's implementation is called. Can you please explain me what happens under the hood?
Thanks in advance
Nick
It works like this. Imagine the compiler rewrote your classes into this:
class VTable
{
public VTable(Func<Animal, string> eat)
{
this.AnimalEat = eat;
}
public readonly Func<Animal, string> AnimalEat;
}
class Animal
{
private static AnimalVTable = new VTable(Animal.AnimalEat);
private static string AnimalEat(Animal _this)
{
return "undefined";
}
public VTable VTable;
public static Animal CreateAnimal()
{
return new Animal()
{ VTable = AnimalVTable };
}
}
class Human : Animal
{
private static HumanVTable = new VTable(Human.HumanEat);
private static string HumanEat(Animal _this)
{
return "human";
}
public static Human CreateHuman()
{
return new Human()
{ VTable = HumanVTable };
}
}
class Dog : Animal
{
public static string DogEat(Dog _this) { return "dog"; }
public static Dog CreateDog()
{
return new Dog()
{ VTable = AnimalVTable } ;
}
}
Now consider these calls:
Animal animal;
Dog dog;
animal = new Human();
animal.Eat();
animal = new Animal();
animal.Eat();
dog = new Dog();
dog.Eat();
animal = dog;
animal.Eat();
The compiler reasons as follows: If the type of the receiver is Animal then the call to Eat must be to animal.VTable.AnimalEat. If the type of the receiver is Dog then the call must be to DogEat. So the compiler writes these as:
Animal animal;
Dog dog;
animal = Human.CreateHuman(); // sets the VTable field to HumanVTable
animal.VTable.AnimalEat(animal); // calls HumanVTable.AnimalEat
animal = Animal.CreateAnimal(); // sets the VTable field to AnimalVTable
animal.VTable.AnimalEat(animal); // calls AnimalVTable.AnimalEat
dog = Dog.CreateDog(); // sets the VTable field to AnimalVTable
Dog.DogEat(dog); // calls DogEat, obviously
animal = dog;
animal.VTable.AnimalEat(animal); // calls AnimalVTable.AnimalEat
That is exactly how it works. The compiler generates vtables for you behind the scenes, and decides at compile time whether to call through the vtable or not based on the rules of overload resolution.
The vtables are set up by the memory allocator when the object is created. (My sketch is a lie in this regard, since the vtable is set up before the ctor is called, not after.)
The "this" of a virtual method is actually secretly passed as an invisible formal parameter to the method.
Make sense?
I understand in the memory _animal contains an address which will point to Human or Dog object. How does it decide which function to invoke.
Like data, code also has an address.
Therefore the typical approach to this problem is for Human or Dog objects to contain the address of the code of their methods. This is sometimes called using a vtable. In a language like C or C++ this concept is also directly exposed as what's called a function pointer.
Now, you've mentioned C#, which has a pretty high-level type system, in which types of objects are also discernible at runtime.... Therefore the implementation details may differ from the traditional approach in some way. But, as to your question, the function pointer/v-table concept is one way to do it, and it would surprise me if .NET has strayed too much from this.
In C#, derived classes must provide the override modifier for any overridden method inherited from a base class.
Animal _animal = new Human();
It's not just the Human object got constructed. They are two sub-objects. One is Animal sub-object and the other is Human sub-object.
Console.WriteLine(_animal.Eat());
When made the call to _animal.Eat();, the run time checks whether the base class method ( i.e., Eat() )is overridden in the derived class. Since, it is overridden, the corresponding derived class method is called. Hence the output -
Eat like a Human
But, in case of -
_animal = new Dog();
Console.WriteLine(_animal.Eat());
In the Dog, there is no Eat() overridden method in the derived class Dog. So, base class method itself is called. Also this method of checking is done because in the base class, Eat() is mentioned as virtual and calling mechanism is decided at run-time. To sum up, virtual calling mechanism is a run-time mechanism.
In C# I have three classes: Person, Cat, and Dog.
Both the Cat and Dog classes have the method Eat().
I want the Person class to have a property ‘Pet’.
I want to be able to call the Eat method of both the Cat and Dog via the Person via something like Person.Pet.Eat() but I can’t because the Pet property needs to be either of type Cat or Dog.
Currently I’m getting round this with two properties in the Person class: PetDog and PetCat.
This is okay for now, but if I wanted a 100 different types of animal as pets then I don’t really want to have 100 different Pet properties in the Person class.
Is there a way round this using Interfaces or Inheritance? Is there a way I can set Pet to be of type Object but still access the properties of whichever animal class is assigned to it?
You could have the pets derive from a common base class:
public abstract class Animal
{
protected Animal() { }
public abstract void Eat();
}
And then have Cat and Dog derive from this base class:
public class Cat: Animal
{
public override void Eat()
{
// TODO: Provide an implementation for an eating cat
}
}
public class Dog: Animal
{
public override void Eat()
{
// TODO: Provide an implementation for an eating dog
}
}
And your Person class will have a property of type Animal:
public class Person
{
public Animal Pet { get; set; }
}
And when you have an instance of Person:
var person = new Person
{
Pet = new Cat()
};
// This will call the Eat method from the Cat class as the pet is a cat
person.Pet.Eat();
You could also provide some common implementation for the Eat method in the base class to avoid having to override it in the derived classes:
public abstract class Animal
{
protected Animal() { }
public virtual void Eat()
{
// TODO : Provide some common implementation for an eating animal
}
}
Notice that Animal is still an abstract class to prevent it from being instantiated directly.
public class Cat: Animal
{
}
public class Dog: Animal
{
public override void Eat()
{
// TODO: Some specific behavior for an eating dog like
// doing a mess all around his bowl :-)
base.Eat();
}
}
Is there a way round this using Interfaces or Inheritance?
Yes.
Interfaces: make an interface IEat or IPet or whatever concept you want to represent. Make the interface have an Eat method. Have Cat and Dog implement this interface. Have the Pet property be of that type.
Inheritance: Make an abstract base class Animal or Pet or whatever concept you want to represent. Make an abstract method Eat on the base class. Have Cat and Dog inherit from this base class. Have the Pet property be of that type.
What is the difference between these two?
Use interfaces to model the idea "X knows how to do Y". IDisposable, for example, means "I know how to dispose of the important resource that I am holding onto". That is not a fact about what the object is, it is a fact about what the object does.
Use inheritance to model the idea of "X is a kind of Y". A Dog is a kind of Animal.
The thing about interfaces is you can have as many of them as you want. But you only get to inherit directly from one base class, so you have to make sure you get it right if you're going to use inheritance. The problem with inheritance is that people end up making base classes like "Vehicle" and then they say "a MilitaryVehicle is a kind of Vehicle" and "A Ship is a kind of Vehicle" and now you're stuck: what is the base class of Destroyer? It is both a Ship and a MilitaryVehicle and it can't be both. Choose your "inheritance pivot" extremely carefully.
Is there a way I can set Pet to be of type Object but still access the properties of whichever animal class is assigned to it?
Yes, in C# 4 there is, but do not do so. Use interfaces or inheritance.
In C# 4 you can use "dynamic" to get dynamic dispatch at runtime to the Eat method on the object that is in Pet.
The reason you don't want to do this is because this will crash and die horribly should someone put a Fruit or a Handsaw in the Pet property and then try to make it Eat. The point of compile-time checks is to decrease program fragility. If you have a way to make more compile-time checks, use it.
Use an abstract class.
public abstract class Pet { public abstract void Eat(); }
public class Dog : Pet { }
public class Cat : Pet { }
public class Person {
public Pet Pet;
}
I’m sure you can do the rest.
Using an interface;
abstract class Animal
{
public virtual void DoSomething() { }
}
interface ICanEat
{
void Eat();
}
class Dog : Animal, ICanEat
{
public void Eat()
{
Console.Out.WriteLine("Dog eat");
}
}
class Cat : Animal, ICanEat
{
public void Eat()
{
Console.Out.WriteLine("Cat eat");
}
}
class Person
{
public Animal MyAnimal { get; set; }
}
Then you can call
(person.MyAnimal as ICanEat).Eat();
performing the correct null-checks as you go.
Why not create a base class of type Pet
public abstract class Pet{
public abstract void Eat();
}
Have this cat and dog inherit from an interface IPet
public interface IPet
{
bool hungry();
void Eat();
}