Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to allow Class Property be of multiple/flexible types in c#?

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?

like image 800
Caustix Avatar asked Sep 07 '10 17:09

Caustix


People also ask

How do you declare a property in a classroom?

A property inside a class can be declared as abstract by using the keyword abstract. Remember that an abstract property in a class carries no code at all.

Why do we use get and set properties in C#?

A get property accessor is used to return the property value, and a set property accessor is used to assign a new value. In C# 9 and later, an init property accessor is used to assign a new value only during object construction. These accessors can have different access levels.

Can we have private properties in C#?

Properties can be marked as public , private , protected , internal , protected internal , or private protected . These access modifiers define how users of the class can access the property. The get and set accessors for the same property may have different access modifiers.

What is property explain read/write property with proper syntax and example?

The Read-Write Property is used for both reading the data from the data field as well as writing the data into the data field of a class. This property will contain two accessors i.e. set and get. The set accessor is used to set or write the value to a data field and the get accessor is read the data from a variable.


2 Answers

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();
    }
}
like image 162
Darin Dimitrov Avatar answered Oct 06 '22 01:10

Darin Dimitrov


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.

like image 35
Eric Lippert Avatar answered Oct 06 '22 01:10

Eric Lippert