11

Given the following code, I have inherited a class Circle from Shape:

class Shape
{
    void Draw();
}

class Circle : Shape
{
}

void Main(string[] args)
{
    Shape s = new Shape();
    Shape s2 = new Shape();
    Circle c = new Circle();

    List<Shape> ShapeList = new List<Shape>();

    ShapeList.Add(s);
    ShapeList.Add(s2);
    ShapeList.Add(c);
}

How can c be added into the ShapeList?

Failed Scientist
  • 1,977
  • 3
  • 29
  • 48

5 Answers5

10

A Circle is a Shape, because Circle extends Shape. Because of that, you can always treat a Circle object as if it were a Shape since we can be absolutely sure that all of the operations that can be performed on a Shape can also be performed on a Circle.

Servy
  • 202,030
  • 26
  • 332
  • 449
  • [Boxing and Unboxing (C# Programming Guide)](http://msdn.microsoft.com/en-us/library/yz2be5wk.aspx) – Monso Feb 20 '13 at 17:38
  • 4
    @JMonsorno I fail to see how boxing is relevant here. There are no value types here, and implicit boxing only applies to value types. – Servy Feb 20 '13 at 17:39
  • @JMonsorno No, the circle is not boxed at all. Perhaps you should read your own link. The circle is not a value type, nor is it being converted to `object` or a variable of an interface type, so the first sentence of your link pretty clearly tells us it's not relevant. – Servy Feb 20 '13 at 17:41
  • The Circle is getting boxed into a Shape to go into the list of type Shape ` Shape circleAsShape = ShapeList.Last(); Circle circleAsCircle = (Circle) circleAsShape //unbox ` – Monso Feb 20 '13 at 17:42
  • @JMonsorno Again, no, that is not boxing at all. You should really read your own link to understand what boxing actually entails. No boxing conversion needs to take place to convert the `Circle` into a `Shape`, it is already a `Shape` without needing to do anything to it, which is different from say an `int`, which requires a boxing conversion to allow it to be stored in a variable of type `object`. – Servy Feb 20 '13 at 17:43
  • @JMonsorno, I thought on similar lines but "boxing" is not correct word here since all classes are reference types. I had boxing in my mind coz since Circle is added to Shape List, it is like Circle object virtually getting converted to Shape object since its inherited class and contains all behavior of Shape. – Sunny Feb 20 '13 at 17:45
  • No, scroll down a bit and read the article. It is most definitely being boxed and int does not an explicit boxing which is also mentions: object o = i; "but explicit boxing is never required:" – Monso Feb 20 '13 at 17:47
  • @Sundeep There's a more fundamental flaw in your thinking. You're thinking about how to *convert* a `Circle` to a `Shape`, as if some operation needs to be performed on it for it to be able to be a shape. *That's just not the case.* A `Circle` *is already a `Shape`*, without you needing to do *anything*, it just *is*. – Servy Feb 20 '13 at 17:47
  • 2
    @JMonsorno I *highly* suggest you read the entire article, start to finish, before responding again. I can assure you that boxing has nothing at all to do with this question, and you are only making yourself look bad by asserting it's relevant. Implicit language boxing only applies to value types; there are no value types here, so boxing does not apply. – Servy Feb 20 '13 at 17:49
  • "int does not an explicit boxing which is also mentions: object o = i; 'but explicit boxing is never required:'" `int` doesn't need an *explicit* boxing call because it will be *implicitly* boxed. It will still need to be boxed to be stored in a variable of type `object` however. – Servy Feb 20 '13 at 17:50
  • @JMonsorno "an int is already an object, what's your point" The entire purpose for the existence of boxing is that an `int` is *not* an object, it must first be boxed in order to become an object. That you don't understand this only cements the fact that you don't grasp the fundamental concept of boxing. – Servy Feb 20 '13 at 17:52
  • @Servy, thanks for the learning. One quick question, suppose I only add two Circle objects to ShapeList. And now, can I retrieve those objects from ShapeList and cast them back to Circle. – Sunny Feb 20 '13 at 17:54
  • @Sundeep You can, but in general you shouldn't be; it would be a sign of poor design if you had to. In general, if you have a `List`, you're saying that "as long as the object has all of the operations that a `Shape` has, that's good enough for me, I can work with that". If you actually need behavior specific to a `Circle`, then you should have a `List`. In most situations using a cast is a sign that there is a design flaw somewhere (but sometimes it's not possible or worthwhile to fix, so casts are still used and useful). – Servy Feb 20 '13 at 17:59
1

I believe this is an example of polymorphism. Since Circle is derived from Shape, polymorphism allows us to treat it as it's base type (letting you insert it into a list of type Shape)

Abe Miessler
  • 82,532
  • 99
  • 305
  • 486
1

Circle extends Shape, which means, it inherits all properties & methods from it. Circle is kind of "superset" of Shape. Considering it you can use it as if it were a Shape. What you can't do is the other way around, namely to insert a shape into a list of Circles. Think of it logically. You have a bunch of Shapes. These can be Circles, Squares, Triangles, etc. But if you have a bunch of Circles, they must specifically be Circles and not a general Shape.

Stefanos Kargas
  • 10,547
  • 22
  • 76
  • 101
1

Leave the programming part, logically every circle, rectangle.. everything is a shape. Its just like you are making a list of contacts in your Phone. Some contacts have a T-mobile connection, some use Vodafone, some use Orange, but all are phones and you add them in your list in exactly same manner without any difference. You can take this list to apply polymorphism as well by calling different contacts: Your calling mechanism will be exactly same but on the run-time (calling) it will be decided which phone service did this contact have.

Dev
  • 21
  • 4
0

This is about covariance and contravariance in generics. See http://msdn.microsoft.com/en-us/library/dd799517.aspx to get some concept about that.

  • This has nothing to do with either. `List` is actually *invariant* in `T`; it is neither covariant nor contravariant, which is why you can't add a `List` to a `List>` (which is an example for which covariance is relevant). – Servy Feb 20 '13 at 17:53
  • Servy, in fact, code compiles and runs. What would be the correct approach then? – Lucas Bataglião Feb 20 '13 at 18:05
  • What do you mean it compiles and runs? Are you referring to the OP's code? If so, yes, it compiles and runs, but the reason that it works has nothing to do with generic covariance or contravariance. `List` is invariant, so it wouldn't work if it did rely on either. The fact that it does tells you they're not related concepts. If `List` were covariant then this would compile, but since it's invariant it won't: `List> list = new List>(); list.Add(new List());`. – Servy Feb 20 '13 at 18:08