Raf
Raf

Reputation: 33

How to save differently-typed values without converting them and thus losing their specific fields/methods in C#?

I'm trying out C# for the first time, so I apologize if this has a simple solution or if the language simply does not allow it.


I'll simplify my problem to the best of my ability - Imagine I have the following classes:

public class Animal
{
    public bool isAlive = true;
    public List<Animal> friends;
}

public class Dog : Animal
{
    public string Bark()
    {
        return "Woof!";
    }
}

public class Cat : Animal
{
    public bool hatesMe = true;
}

public class GoldenRetriever : Dog
{
    public bool greatForFamilies = true;
}

Now, the following code:

var Chuck = new GoldenRetriever();
var Stripey = new Cat();
Chuck.friends.Add(Stripey);

var myVar1 = Stripey.hatesMe; //fine
var myVar2 = Chuck.friends[0].hatesMe; //error

I know that when I added Stripey to Chuck's friends list, Stripey was converted to an Animal and lost its Cat members - my problem is: how can I have a list/array/collection of different types, without them losing their specific members?


Thanks in advance!

Upvotes: 1

Views: 107

Answers (2)

InputOutput
InputOutput

Reputation: 61

Twenty is right. You need need cast the class Animal to Cat before you can access the 'hatesMe' field:

var myVar2 = ((Cat)Chuck.friends[0]).hatesMe;

But if the type of Animal is unknown you could work with virtual/override properties:

public class Animal
{
    public bool isAlive = true;
    public List<Animal> friends;

    public virtual bool HatesMe
    {
        get
        {
            return false;
        }
    }
}

public class Dog : Animal
{
    public string Bark()
    {
        return "Woof!";
    }

}

public class Cat : Animal
{
    public override bool HatesMe
    {
        get
        {
            return true;
        }
    }
}

public class GoldenRetriever : Dog
{
    public bool greatForFamilies = true;
}

Now the property 'HatesMe' works with all classes which are inherited from Animal:

var Chuck = new GoldenRetriever();
var Stripey = new Cat();
Chuck.friends.Add(Stripey);

var myVar1 = Stripey.hatesMe; //fine
var myVar2 = Chuck.friends[0].HatesMe; //fine

In case the type of Animal is unknown but the given class structure shouldn't be touched you could access the 'hatesMe' field through reflection using the dynamic keyword:

dynamic Stripey = new Cat();
bool b = Stripey.hatesMe; //fine

Be aware, accessing fields through reflection is slow. Furthermore if you rename the 'hatesMe' field without adapting the dynamic code, the code will throw an exception.

Upvotes: 0

Twenty
Twenty

Reputation: 5901

Actually you are not losing any Data, while storing it in its base type. To access the given data, you need to convert it to the data type which inherits the base type. In your case you need to cast it to Cat in order to access the hatesMe field. This would look something like the code below.

var myVar2 = ((Cat)Chuck.friends[0]).hatesMe;

In simple words, when storing an object in a datatype which it implements or inherits, you are only hiding its other members.

Upvotes: 2

Related Questions