0

Say I have three classes that look like this:

abstract class Fruit
{
     public string name { get; set; }
}

class Apple : Fruit
{
     public int redness { get; set; }
}

class Pear : Fruit
{
     public int size { get; set; }
}

And somewhere else I have:

List<Fruit> delicious_things = new List<Fruit>{
      new Pear(){}
      new Apple(){}
}

How do I access, as an example the pear.size from delicious_things?

If I know already that Pear is delicious_things[0], I could do: delicious_things[0].size, but that doesn't seem to work.

What am I missing? Thanks in advance!

Olive
  • 3,516
  • 7
  • 24
  • 32
  • Consider interfaces and unification around such (or, since there is subtyping, around the base type) - I would argue that different types of fruit probably all have "color" and "size" characteristics. – user2864740 Apr 03 '14 at 23:12

3 Answers3

4

In order to access specific properties you need to perform a cast.Also you should consider using as or is operators when performing casts.Because if you try to perform a cast from one incompatible type to another (for ex. from Apple to Pear) you will get an InvalidCastException:

var pear = delicious_things[0] as Pear;
int size;
if(pear != null) size = pear.size;

Or:

if(delicious_things[0] is Pear)
{
   int size = ((Pear)delicious_things[0]).size; 
}
Selman Genç
  • 100,147
  • 13
  • 119
  • 184
  • this appears to be the only answer that doesn't blow up if you don't have a pear – failedprogramming Apr 03 '14 at 23:44
  • @failedprogramming - I think that is because the question asked `If I know already that Pear is delicious_things[0]` – Oren Hizkiya Apr 04 '14 at 00:07
  • @Oren regardless of how the question was asked, it does not change the fact that this answer can handle a no pear situation. While your answer fits within the parameters of this question, I'm just saying I personally prefer this one as it can achieve more. No disrespect intended. – failedprogramming Apr 04 '14 at 00:48
  • @failedprogramming - Agreed - Probably more educational for a beginner to see the use of the `as` and `is` operators. – Oren Hizkiya Apr 04 '14 at 00:51
3

You would have to cast the item to the specific type.

((Pear)delicious_things[0]).size

However, this is not good design. See Why should casting be avoided?

Community
  • 1
  • 1
Oren Hizkiya
  • 4,420
  • 2
  • 23
  • 33
  • Thanks! As a followup: Can I somehow see the type/class of [0] in that list? – Olive Apr 03 '14 at 23:08
  • You can set a debug point and inspect `delicious_things` and it will show you the concrete types of each item. – Oren Hizkiya Apr 03 '14 at 23:09
  • Is there a way to do it without debugging? – Olive Apr 03 '14 at 23:11
  • 3
    You should probably rethink your design. If you are constantly downcasting your items.. you've done something wrong. Code shouldn't be littered with casts like this everywhere. – Simon Whitehead Apr 03 '14 at 23:11
  • Using the `GetType()` method. Though as mentioned, if you are thinking about doing it this way, you're probably doing it wrong. – Matt Apr 03 '14 at 23:11
2

what you can do to filter for a specific type is:

delicious_things.OfType<Pear>().First().size;

like that you are sure its gonna take the first Pear without casting the objects.

Of course you are still not sure if the list contains at least one element of type Pear

think always about all possibilities --> otherwise once in the future you will fall over it

fixagon
  • 5,506
  • 22
  • 26