c# stacking different classes in the same list












0















I'm learning inheritance and have a few questions:




  • Assuming I have a base class A.


  • Class B and class C are different classes that inherit from A.




    1. Assuming I want to stack in the same list instances of class B and C,
      what is the type of the list should be? List<object> or List<A> ?


    2. Why List<A> can hold the data of class B and C if Class A has fewer fields? I would expect that List<A> will trim the extra fields of class B and C inside the list, but I saw a working example of it.


    3. When looping the list with foreach how can I tell if the object is class B or C?





Thank you!










share|improve this question

























  • The point of inheritance is to reuse code. The point of polymorphism is to hide the implementation from the calling code by providing a common interface. So, if you are doing proper OOP (SOLID principles are a good starting point), then placing instances of different classes into the same list only makes sense if they share the same interface. For the caller, all the object in that list will be instances of A. If you need to check the type of the object inside the foreach loop, you're doing it wrong.

    – Groo
    Nov 25 '18 at 21:20













  • An Interface is your friend. Anyway, if you add a B or C class to a List<A> and check List<A>[N] is B, List<A>[N] is C, the test will return the actual class stored at that index. You can then cast to the right class (it may not be even necessary, depending on what you're doing with it).

    – Jimi
    Nov 25 '18 at 21:26













  • 2. class A is a Reference Type, hence only references are stored in that list (like a reference counting C++ pointer)

    – Dennis Kuypers
    Nov 25 '18 at 23:07
















0















I'm learning inheritance and have a few questions:




  • Assuming I have a base class A.


  • Class B and class C are different classes that inherit from A.




    1. Assuming I want to stack in the same list instances of class B and C,
      what is the type of the list should be? List<object> or List<A> ?


    2. Why List<A> can hold the data of class B and C if Class A has fewer fields? I would expect that List<A> will trim the extra fields of class B and C inside the list, but I saw a working example of it.


    3. When looping the list with foreach how can I tell if the object is class B or C?





Thank you!










share|improve this question

























  • The point of inheritance is to reuse code. The point of polymorphism is to hide the implementation from the calling code by providing a common interface. So, if you are doing proper OOP (SOLID principles are a good starting point), then placing instances of different classes into the same list only makes sense if they share the same interface. For the caller, all the object in that list will be instances of A. If you need to check the type of the object inside the foreach loop, you're doing it wrong.

    – Groo
    Nov 25 '18 at 21:20













  • An Interface is your friend. Anyway, if you add a B or C class to a List<A> and check List<A>[N] is B, List<A>[N] is C, the test will return the actual class stored at that index. You can then cast to the right class (it may not be even necessary, depending on what you're doing with it).

    – Jimi
    Nov 25 '18 at 21:26













  • 2. class A is a Reference Type, hence only references are stored in that list (like a reference counting C++ pointer)

    – Dennis Kuypers
    Nov 25 '18 at 23:07














0












0








0








I'm learning inheritance and have a few questions:




  • Assuming I have a base class A.


  • Class B and class C are different classes that inherit from A.




    1. Assuming I want to stack in the same list instances of class B and C,
      what is the type of the list should be? List<object> or List<A> ?


    2. Why List<A> can hold the data of class B and C if Class A has fewer fields? I would expect that List<A> will trim the extra fields of class B and C inside the list, but I saw a working example of it.


    3. When looping the list with foreach how can I tell if the object is class B or C?





Thank you!










share|improve this question
















I'm learning inheritance and have a few questions:




  • Assuming I have a base class A.


  • Class B and class C are different classes that inherit from A.




    1. Assuming I want to stack in the same list instances of class B and C,
      what is the type of the list should be? List<object> or List<A> ?


    2. Why List<A> can hold the data of class B and C if Class A has fewer fields? I would expect that List<A> will trim the extra fields of class B and C inside the list, but I saw a working example of it.


    3. When looping the list with foreach how can I tell if the object is class B or C?





Thank you!







c# list inheritance






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 25 '18 at 21:16









Olivier Jacot-Descombes

68.6k890141




68.6k890141










asked Nov 25 '18 at 20:57









Sasha VasserfirerSasha Vasserfirer

73




73













  • The point of inheritance is to reuse code. The point of polymorphism is to hide the implementation from the calling code by providing a common interface. So, if you are doing proper OOP (SOLID principles are a good starting point), then placing instances of different classes into the same list only makes sense if they share the same interface. For the caller, all the object in that list will be instances of A. If you need to check the type of the object inside the foreach loop, you're doing it wrong.

    – Groo
    Nov 25 '18 at 21:20













  • An Interface is your friend. Anyway, if you add a B or C class to a List<A> and check List<A>[N] is B, List<A>[N] is C, the test will return the actual class stored at that index. You can then cast to the right class (it may not be even necessary, depending on what you're doing with it).

    – Jimi
    Nov 25 '18 at 21:26













  • 2. class A is a Reference Type, hence only references are stored in that list (like a reference counting C++ pointer)

    – Dennis Kuypers
    Nov 25 '18 at 23:07



















  • The point of inheritance is to reuse code. The point of polymorphism is to hide the implementation from the calling code by providing a common interface. So, if you are doing proper OOP (SOLID principles are a good starting point), then placing instances of different classes into the same list only makes sense if they share the same interface. For the caller, all the object in that list will be instances of A. If you need to check the type of the object inside the foreach loop, you're doing it wrong.

    – Groo
    Nov 25 '18 at 21:20













  • An Interface is your friend. Anyway, if you add a B or C class to a List<A> and check List<A>[N] is B, List<A>[N] is C, the test will return the actual class stored at that index. You can then cast to the right class (it may not be even necessary, depending on what you're doing with it).

    – Jimi
    Nov 25 '18 at 21:26













  • 2. class A is a Reference Type, hence only references are stored in that list (like a reference counting C++ pointer)

    – Dennis Kuypers
    Nov 25 '18 at 23:07

















The point of inheritance is to reuse code. The point of polymorphism is to hide the implementation from the calling code by providing a common interface. So, if you are doing proper OOP (SOLID principles are a good starting point), then placing instances of different classes into the same list only makes sense if they share the same interface. For the caller, all the object in that list will be instances of A. If you need to check the type of the object inside the foreach loop, you're doing it wrong.

– Groo
Nov 25 '18 at 21:20







The point of inheritance is to reuse code. The point of polymorphism is to hide the implementation from the calling code by providing a common interface. So, if you are doing proper OOP (SOLID principles are a good starting point), then placing instances of different classes into the same list only makes sense if they share the same interface. For the caller, all the object in that list will be instances of A. If you need to check the type of the object inside the foreach loop, you're doing it wrong.

– Groo
Nov 25 '18 at 21:20















An Interface is your friend. Anyway, if you add a B or C class to a List<A> and check List<A>[N] is B, List<A>[N] is C, the test will return the actual class stored at that index. You can then cast to the right class (it may not be even necessary, depending on what you're doing with it).

– Jimi
Nov 25 '18 at 21:26







An Interface is your friend. Anyway, if you add a B or C class to a List<A> and check List<A>[N] is B, List<A>[N] is C, the test will return the actual class stored at that index. You can then cast to the right class (it may not be even necessary, depending on what you're doing with it).

– Jimi
Nov 25 '18 at 21:26















2. class A is a Reference Type, hence only references are stored in that list (like a reference counting C++ pointer)

– Dennis Kuypers
Nov 25 '18 at 23:07





2. class A is a Reference Type, hence only references are stored in that list (like a reference counting C++ pointer)

– Dennis Kuypers
Nov 25 '18 at 23:07












3 Answers
3






active

oldest

votes


















1














Its basic oop (object oriented proggreming) principall called polymorphisem




  1. you shoud use listList<A>


  2. when you put B type object into List<A> its like to look on B as A. so you can access th A fields that it inherits


  3. you can use the is statement.
    for example if (someObject is B)



you can reed more here polymorphisem docs






share|improve this answer































    1















    1. The the type parameter of the list must be the nearest common ancestor of B and C: here List<A>. List<object> would also work, but at the cost that it is weakly typed and allows you add any kind of objects: strings integers, dates, persons. Which is probably not the intention here.


    2. Class types are reference types. This means that the list only contains references to objects of different length, that are not themselves in the list. I.e. no truncation occurs. This is also the reason why value types can not be inherited. You cannot inherit from an int or from a struct like DateTime.


    3. Let's imagine a better example for this question



    public abstract class : Shape
    {
    }

    public class Rectangle : Shape
    {
    public double Width { get; set; }
    public double Height { get; set; }
    }

    public class Circle : Shape
    {
    public double Radius { get; set; }
    }


    Now, let us calculate the total area of shapes in a list List<shape> shapes:



    double totalArea = 0.0;
    foreach (Shape shape in shapes) {
    if (shape is Rectangle rect) {
    totalArea += rect.Width * rect.Height;
    } else if (shape is Circle circle) {
    totalArea += circle.Radius * circle.Radius * Math.Pi;
    }
    }


    or



    double totalArea = 0.0;
    foreach (Shape shape in shapes) {
    switch (shape)
    {
    case Rectangle rect:
    totalArea += rect.Width * rect.Height;
    break;
    case Circle circle:
    totalArea += circle.Radius * circle.Radius * Math.Pi;
    break;
    }
    }


    But generally it is better if you don't need to know the type. E.g. Instead of using the switch in the last example, let the classes themselves do the job



    public abstract class : Shape
    {
    public abstract double Area { get; }
    }

    public class Rectangle : Shape
    {
    public double Width { get; set; }
    public double Height { get; set; }

    public override double Area => Width * Height;
    }

    public class Circle : Shape
    {
    public double Radius { get; set; }

    public override double Area => Radius * Radius * Math.Pi;
    }


    Then the loop becomes



    double totalArea = 0.0;
    foreach (Shape shape in shapes) {
    totalArea += shape.Area;
    }


    This is called polymorphism (multi-shaped). In this case shape can be a Rectangle or a Circle. But you don't have to care. shape.Area will automatically call Rectangle.Area for Rectangle objects and Circle.Area for Circle objects. This is the true power of object orientation, where as the solutions with if or switch are a procedural approach.






    share|improve this answer


























    • Thank you very much for the answers! Regarding question 3, you showed how we can access the same methode (differently implemented) of each class without the if or switch statment. But how to access specific properties that only class B and C are possessed?

      – Sasha Vasserfirer
      Nov 26 '18 at 4:46













    • You have two possibilities: 1. By using these if or switch. 2. By using these properties in common methods or other properties. E.g. If the base class is a Shape with two derived classes Rectangle with Length and Width properties and Circle with a Radius, then calculate the area in a common property Area instead of accessing the new properties from outside with if or switch.

      – Olivier Jacot-Descombes
      Nov 26 '18 at 13:53











    • I included a better example in my answer.

      – Olivier Jacot-Descombes
      Nov 26 '18 at 15:32



















    0














    If you have a List<A>, you can use it for each class of the type of A and all derived classes. Lets take it to the real world:



    If you have a definition Vehicle (that's your A). You could write a software for a car rental company which handles vehicles. They have all sorts for vehicles like one or more bikes (that's B) and one or more cars (that's C). Both are very different but both are vehicles.



    By using the abstraction of a Vehicle (A), you can store bikes and cars in the same context.



    So in a List<Vehicle>, you could store bikes, cars, trucks and all sort of movable stuff. However, the definition Vehicle will have the least common denominator like the kind of motor, the count of doors, etc. But you would (hopefully) not find truck-specific properties on that definition of vehicle which might not fit to others like a bike or a car.



    Tracking bikes and cars as vehicles does not strip of the fields at all. However, they are treated as vehicles, that's why you would not see the specific properties until you cast each vehicle to its real type. There are some approaches to this, I'd like to highlight Pattern Matching in C# 7 which makes it really easy by now.



    foreach (var v in vehicleList)
    {
    switch (v)
    {
    case Bike b:
    // ... do bike specific things
    break;
    case Car c:
    // ... do car specific things
    break;
    case Truck t:
    // ... do truck specific things
    break;
    default:
    WriteLine("<unknown>");
    break;
    }
    }





    share|improve this answer





















    • 1





      Pattern matching is neat, but OOP was invented precisely to avoid this type of code.

      – Groo
      Nov 25 '18 at 21:23











    • Good point, actually. I just wanted to show that the values are not lost if you recover the real type from the common vehicle list.

      – Waescher
      Nov 25 '18 at 21:24











    • @Groo - "invented precisely to avoid this type of code" - What? No, it was invented to precisely allow this kind of code. Do you have a reference to avoiding it?

      – Enigmativity
      Nov 25 '18 at 21:39






    • 1





      @Enigmativity: I am not sure what you are referring to with "precisely allow". Polymorphism means abstracting the actual object type and hiding the actual implementation through its interface (which is violated in this example which knows specifics of each subclass). Single responsibility principle states that a class should have single reason to change (violated here, you will need to update each switch/case in your program when you add a Boat). This code is basically the school example for refactoring into OO code.

      – Groo
      Nov 25 '18 at 22:15











    • @Groo - OOP wasn't invented with the SOLID principles. They came along later. OOP was invented to allow polymorphism. When I said "precisely allow" I was referring to your line "invented precisely to avoid this type of code".

      – Enigmativity
      Nov 25 '18 at 22:19











    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53471900%2fc-sharp-stacking-different-classes-in-the-same-list%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    3 Answers
    3






    active

    oldest

    votes








    3 Answers
    3






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    1














    Its basic oop (object oriented proggreming) principall called polymorphisem




    1. you shoud use listList<A>


    2. when you put B type object into List<A> its like to look on B as A. so you can access th A fields that it inherits


    3. you can use the is statement.
      for example if (someObject is B)



    you can reed more here polymorphisem docs






    share|improve this answer




























      1














      Its basic oop (object oriented proggreming) principall called polymorphisem




      1. you shoud use listList<A>


      2. when you put B type object into List<A> its like to look on B as A. so you can access th A fields that it inherits


      3. you can use the is statement.
        for example if (someObject is B)



      you can reed more here polymorphisem docs






      share|improve this answer


























        1












        1








        1







        Its basic oop (object oriented proggreming) principall called polymorphisem




        1. you shoud use listList<A>


        2. when you put B type object into List<A> its like to look on B as A. so you can access th A fields that it inherits


        3. you can use the is statement.
          for example if (someObject is B)



        you can reed more here polymorphisem docs






        share|improve this answer













        Its basic oop (object oriented proggreming) principall called polymorphisem




        1. you shoud use listList<A>


        2. when you put B type object into List<A> its like to look on B as A. so you can access th A fields that it inherits


        3. you can use the is statement.
          for example if (someObject is B)



        you can reed more here polymorphisem docs







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Nov 25 '18 at 21:28









        tomastomas

        10011




        10011

























            1















            1. The the type parameter of the list must be the nearest common ancestor of B and C: here List<A>. List<object> would also work, but at the cost that it is weakly typed and allows you add any kind of objects: strings integers, dates, persons. Which is probably not the intention here.


            2. Class types are reference types. This means that the list only contains references to objects of different length, that are not themselves in the list. I.e. no truncation occurs. This is also the reason why value types can not be inherited. You cannot inherit from an int or from a struct like DateTime.


            3. Let's imagine a better example for this question



            public abstract class : Shape
            {
            }

            public class Rectangle : Shape
            {
            public double Width { get; set; }
            public double Height { get; set; }
            }

            public class Circle : Shape
            {
            public double Radius { get; set; }
            }


            Now, let us calculate the total area of shapes in a list List<shape> shapes:



            double totalArea = 0.0;
            foreach (Shape shape in shapes) {
            if (shape is Rectangle rect) {
            totalArea += rect.Width * rect.Height;
            } else if (shape is Circle circle) {
            totalArea += circle.Radius * circle.Radius * Math.Pi;
            }
            }


            or



            double totalArea = 0.0;
            foreach (Shape shape in shapes) {
            switch (shape)
            {
            case Rectangle rect:
            totalArea += rect.Width * rect.Height;
            break;
            case Circle circle:
            totalArea += circle.Radius * circle.Radius * Math.Pi;
            break;
            }
            }


            But generally it is better if you don't need to know the type. E.g. Instead of using the switch in the last example, let the classes themselves do the job



            public abstract class : Shape
            {
            public abstract double Area { get; }
            }

            public class Rectangle : Shape
            {
            public double Width { get; set; }
            public double Height { get; set; }

            public override double Area => Width * Height;
            }

            public class Circle : Shape
            {
            public double Radius { get; set; }

            public override double Area => Radius * Radius * Math.Pi;
            }


            Then the loop becomes



            double totalArea = 0.0;
            foreach (Shape shape in shapes) {
            totalArea += shape.Area;
            }


            This is called polymorphism (multi-shaped). In this case shape can be a Rectangle or a Circle. But you don't have to care. shape.Area will automatically call Rectangle.Area for Rectangle objects and Circle.Area for Circle objects. This is the true power of object orientation, where as the solutions with if or switch are a procedural approach.






            share|improve this answer


























            • Thank you very much for the answers! Regarding question 3, you showed how we can access the same methode (differently implemented) of each class without the if or switch statment. But how to access specific properties that only class B and C are possessed?

              – Sasha Vasserfirer
              Nov 26 '18 at 4:46













            • You have two possibilities: 1. By using these if or switch. 2. By using these properties in common methods or other properties. E.g. If the base class is a Shape with two derived classes Rectangle with Length and Width properties and Circle with a Radius, then calculate the area in a common property Area instead of accessing the new properties from outside with if or switch.

              – Olivier Jacot-Descombes
              Nov 26 '18 at 13:53











            • I included a better example in my answer.

              – Olivier Jacot-Descombes
              Nov 26 '18 at 15:32
















            1















            1. The the type parameter of the list must be the nearest common ancestor of B and C: here List<A>. List<object> would also work, but at the cost that it is weakly typed and allows you add any kind of objects: strings integers, dates, persons. Which is probably not the intention here.


            2. Class types are reference types. This means that the list only contains references to objects of different length, that are not themselves in the list. I.e. no truncation occurs. This is also the reason why value types can not be inherited. You cannot inherit from an int or from a struct like DateTime.


            3. Let's imagine a better example for this question



            public abstract class : Shape
            {
            }

            public class Rectangle : Shape
            {
            public double Width { get; set; }
            public double Height { get; set; }
            }

            public class Circle : Shape
            {
            public double Radius { get; set; }
            }


            Now, let us calculate the total area of shapes in a list List<shape> shapes:



            double totalArea = 0.0;
            foreach (Shape shape in shapes) {
            if (shape is Rectangle rect) {
            totalArea += rect.Width * rect.Height;
            } else if (shape is Circle circle) {
            totalArea += circle.Radius * circle.Radius * Math.Pi;
            }
            }


            or



            double totalArea = 0.0;
            foreach (Shape shape in shapes) {
            switch (shape)
            {
            case Rectangle rect:
            totalArea += rect.Width * rect.Height;
            break;
            case Circle circle:
            totalArea += circle.Radius * circle.Radius * Math.Pi;
            break;
            }
            }


            But generally it is better if you don't need to know the type. E.g. Instead of using the switch in the last example, let the classes themselves do the job



            public abstract class : Shape
            {
            public abstract double Area { get; }
            }

            public class Rectangle : Shape
            {
            public double Width { get; set; }
            public double Height { get; set; }

            public override double Area => Width * Height;
            }

            public class Circle : Shape
            {
            public double Radius { get; set; }

            public override double Area => Radius * Radius * Math.Pi;
            }


            Then the loop becomes



            double totalArea = 0.0;
            foreach (Shape shape in shapes) {
            totalArea += shape.Area;
            }


            This is called polymorphism (multi-shaped). In this case shape can be a Rectangle or a Circle. But you don't have to care. shape.Area will automatically call Rectangle.Area for Rectangle objects and Circle.Area for Circle objects. This is the true power of object orientation, where as the solutions with if or switch are a procedural approach.






            share|improve this answer


























            • Thank you very much for the answers! Regarding question 3, you showed how we can access the same methode (differently implemented) of each class without the if or switch statment. But how to access specific properties that only class B and C are possessed?

              – Sasha Vasserfirer
              Nov 26 '18 at 4:46













            • You have two possibilities: 1. By using these if or switch. 2. By using these properties in common methods or other properties. E.g. If the base class is a Shape with two derived classes Rectangle with Length and Width properties and Circle with a Radius, then calculate the area in a common property Area instead of accessing the new properties from outside with if or switch.

              – Olivier Jacot-Descombes
              Nov 26 '18 at 13:53











            • I included a better example in my answer.

              – Olivier Jacot-Descombes
              Nov 26 '18 at 15:32














            1












            1








            1








            1. The the type parameter of the list must be the nearest common ancestor of B and C: here List<A>. List<object> would also work, but at the cost that it is weakly typed and allows you add any kind of objects: strings integers, dates, persons. Which is probably not the intention here.


            2. Class types are reference types. This means that the list only contains references to objects of different length, that are not themselves in the list. I.e. no truncation occurs. This is also the reason why value types can not be inherited. You cannot inherit from an int or from a struct like DateTime.


            3. Let's imagine a better example for this question



            public abstract class : Shape
            {
            }

            public class Rectangle : Shape
            {
            public double Width { get; set; }
            public double Height { get; set; }
            }

            public class Circle : Shape
            {
            public double Radius { get; set; }
            }


            Now, let us calculate the total area of shapes in a list List<shape> shapes:



            double totalArea = 0.0;
            foreach (Shape shape in shapes) {
            if (shape is Rectangle rect) {
            totalArea += rect.Width * rect.Height;
            } else if (shape is Circle circle) {
            totalArea += circle.Radius * circle.Radius * Math.Pi;
            }
            }


            or



            double totalArea = 0.0;
            foreach (Shape shape in shapes) {
            switch (shape)
            {
            case Rectangle rect:
            totalArea += rect.Width * rect.Height;
            break;
            case Circle circle:
            totalArea += circle.Radius * circle.Radius * Math.Pi;
            break;
            }
            }


            But generally it is better if you don't need to know the type. E.g. Instead of using the switch in the last example, let the classes themselves do the job



            public abstract class : Shape
            {
            public abstract double Area { get; }
            }

            public class Rectangle : Shape
            {
            public double Width { get; set; }
            public double Height { get; set; }

            public override double Area => Width * Height;
            }

            public class Circle : Shape
            {
            public double Radius { get; set; }

            public override double Area => Radius * Radius * Math.Pi;
            }


            Then the loop becomes



            double totalArea = 0.0;
            foreach (Shape shape in shapes) {
            totalArea += shape.Area;
            }


            This is called polymorphism (multi-shaped). In this case shape can be a Rectangle or a Circle. But you don't have to care. shape.Area will automatically call Rectangle.Area for Rectangle objects and Circle.Area for Circle objects. This is the true power of object orientation, where as the solutions with if or switch are a procedural approach.






            share|improve this answer
















            1. The the type parameter of the list must be the nearest common ancestor of B and C: here List<A>. List<object> would also work, but at the cost that it is weakly typed and allows you add any kind of objects: strings integers, dates, persons. Which is probably not the intention here.


            2. Class types are reference types. This means that the list only contains references to objects of different length, that are not themselves in the list. I.e. no truncation occurs. This is also the reason why value types can not be inherited. You cannot inherit from an int or from a struct like DateTime.


            3. Let's imagine a better example for this question



            public abstract class : Shape
            {
            }

            public class Rectangle : Shape
            {
            public double Width { get; set; }
            public double Height { get; set; }
            }

            public class Circle : Shape
            {
            public double Radius { get; set; }
            }


            Now, let us calculate the total area of shapes in a list List<shape> shapes:



            double totalArea = 0.0;
            foreach (Shape shape in shapes) {
            if (shape is Rectangle rect) {
            totalArea += rect.Width * rect.Height;
            } else if (shape is Circle circle) {
            totalArea += circle.Radius * circle.Radius * Math.Pi;
            }
            }


            or



            double totalArea = 0.0;
            foreach (Shape shape in shapes) {
            switch (shape)
            {
            case Rectangle rect:
            totalArea += rect.Width * rect.Height;
            break;
            case Circle circle:
            totalArea += circle.Radius * circle.Radius * Math.Pi;
            break;
            }
            }


            But generally it is better if you don't need to know the type. E.g. Instead of using the switch in the last example, let the classes themselves do the job



            public abstract class : Shape
            {
            public abstract double Area { get; }
            }

            public class Rectangle : Shape
            {
            public double Width { get; set; }
            public double Height { get; set; }

            public override double Area => Width * Height;
            }

            public class Circle : Shape
            {
            public double Radius { get; set; }

            public override double Area => Radius * Radius * Math.Pi;
            }


            Then the loop becomes



            double totalArea = 0.0;
            foreach (Shape shape in shapes) {
            totalArea += shape.Area;
            }


            This is called polymorphism (multi-shaped). In this case shape can be a Rectangle or a Circle. But you don't have to care. shape.Area will automatically call Rectangle.Area for Rectangle objects and Circle.Area for Circle objects. This is the true power of object orientation, where as the solutions with if or switch are a procedural approach.







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Nov 26 '18 at 15:37

























            answered Nov 25 '18 at 21:34









            Olivier Jacot-DescombesOlivier Jacot-Descombes

            68.6k890141




            68.6k890141













            • Thank you very much for the answers! Regarding question 3, you showed how we can access the same methode (differently implemented) of each class without the if or switch statment. But how to access specific properties that only class B and C are possessed?

              – Sasha Vasserfirer
              Nov 26 '18 at 4:46













            • You have two possibilities: 1. By using these if or switch. 2. By using these properties in common methods or other properties. E.g. If the base class is a Shape with two derived classes Rectangle with Length and Width properties and Circle with a Radius, then calculate the area in a common property Area instead of accessing the new properties from outside with if or switch.

              – Olivier Jacot-Descombes
              Nov 26 '18 at 13:53











            • I included a better example in my answer.

              – Olivier Jacot-Descombes
              Nov 26 '18 at 15:32



















            • Thank you very much for the answers! Regarding question 3, you showed how we can access the same methode (differently implemented) of each class without the if or switch statment. But how to access specific properties that only class B and C are possessed?

              – Sasha Vasserfirer
              Nov 26 '18 at 4:46













            • You have two possibilities: 1. By using these if or switch. 2. By using these properties in common methods or other properties. E.g. If the base class is a Shape with two derived classes Rectangle with Length and Width properties and Circle with a Radius, then calculate the area in a common property Area instead of accessing the new properties from outside with if or switch.

              – Olivier Jacot-Descombes
              Nov 26 '18 at 13:53











            • I included a better example in my answer.

              – Olivier Jacot-Descombes
              Nov 26 '18 at 15:32

















            Thank you very much for the answers! Regarding question 3, you showed how we can access the same methode (differently implemented) of each class without the if or switch statment. But how to access specific properties that only class B and C are possessed?

            – Sasha Vasserfirer
            Nov 26 '18 at 4:46







            Thank you very much for the answers! Regarding question 3, you showed how we can access the same methode (differently implemented) of each class without the if or switch statment. But how to access specific properties that only class B and C are possessed?

            – Sasha Vasserfirer
            Nov 26 '18 at 4:46















            You have two possibilities: 1. By using these if or switch. 2. By using these properties in common methods or other properties. E.g. If the base class is a Shape with two derived classes Rectangle with Length and Width properties and Circle with a Radius, then calculate the area in a common property Area instead of accessing the new properties from outside with if or switch.

            – Olivier Jacot-Descombes
            Nov 26 '18 at 13:53





            You have two possibilities: 1. By using these if or switch. 2. By using these properties in common methods or other properties. E.g. If the base class is a Shape with two derived classes Rectangle with Length and Width properties and Circle with a Radius, then calculate the area in a common property Area instead of accessing the new properties from outside with if or switch.

            – Olivier Jacot-Descombes
            Nov 26 '18 at 13:53













            I included a better example in my answer.

            – Olivier Jacot-Descombes
            Nov 26 '18 at 15:32





            I included a better example in my answer.

            – Olivier Jacot-Descombes
            Nov 26 '18 at 15:32











            0














            If you have a List<A>, you can use it for each class of the type of A and all derived classes. Lets take it to the real world:



            If you have a definition Vehicle (that's your A). You could write a software for a car rental company which handles vehicles. They have all sorts for vehicles like one or more bikes (that's B) and one or more cars (that's C). Both are very different but both are vehicles.



            By using the abstraction of a Vehicle (A), you can store bikes and cars in the same context.



            So in a List<Vehicle>, you could store bikes, cars, trucks and all sort of movable stuff. However, the definition Vehicle will have the least common denominator like the kind of motor, the count of doors, etc. But you would (hopefully) not find truck-specific properties on that definition of vehicle which might not fit to others like a bike or a car.



            Tracking bikes and cars as vehicles does not strip of the fields at all. However, they are treated as vehicles, that's why you would not see the specific properties until you cast each vehicle to its real type. There are some approaches to this, I'd like to highlight Pattern Matching in C# 7 which makes it really easy by now.



            foreach (var v in vehicleList)
            {
            switch (v)
            {
            case Bike b:
            // ... do bike specific things
            break;
            case Car c:
            // ... do car specific things
            break;
            case Truck t:
            // ... do truck specific things
            break;
            default:
            WriteLine("<unknown>");
            break;
            }
            }





            share|improve this answer





















            • 1





              Pattern matching is neat, but OOP was invented precisely to avoid this type of code.

              – Groo
              Nov 25 '18 at 21:23











            • Good point, actually. I just wanted to show that the values are not lost if you recover the real type from the common vehicle list.

              – Waescher
              Nov 25 '18 at 21:24











            • @Groo - "invented precisely to avoid this type of code" - What? No, it was invented to precisely allow this kind of code. Do you have a reference to avoiding it?

              – Enigmativity
              Nov 25 '18 at 21:39






            • 1





              @Enigmativity: I am not sure what you are referring to with "precisely allow". Polymorphism means abstracting the actual object type and hiding the actual implementation through its interface (which is violated in this example which knows specifics of each subclass). Single responsibility principle states that a class should have single reason to change (violated here, you will need to update each switch/case in your program when you add a Boat). This code is basically the school example for refactoring into OO code.

              – Groo
              Nov 25 '18 at 22:15











            • @Groo - OOP wasn't invented with the SOLID principles. They came along later. OOP was invented to allow polymorphism. When I said "precisely allow" I was referring to your line "invented precisely to avoid this type of code".

              – Enigmativity
              Nov 25 '18 at 22:19
















            0














            If you have a List<A>, you can use it for each class of the type of A and all derived classes. Lets take it to the real world:



            If you have a definition Vehicle (that's your A). You could write a software for a car rental company which handles vehicles. They have all sorts for vehicles like one or more bikes (that's B) and one or more cars (that's C). Both are very different but both are vehicles.



            By using the abstraction of a Vehicle (A), you can store bikes and cars in the same context.



            So in a List<Vehicle>, you could store bikes, cars, trucks and all sort of movable stuff. However, the definition Vehicle will have the least common denominator like the kind of motor, the count of doors, etc. But you would (hopefully) not find truck-specific properties on that definition of vehicle which might not fit to others like a bike or a car.



            Tracking bikes and cars as vehicles does not strip of the fields at all. However, they are treated as vehicles, that's why you would not see the specific properties until you cast each vehicle to its real type. There are some approaches to this, I'd like to highlight Pattern Matching in C# 7 which makes it really easy by now.



            foreach (var v in vehicleList)
            {
            switch (v)
            {
            case Bike b:
            // ... do bike specific things
            break;
            case Car c:
            // ... do car specific things
            break;
            case Truck t:
            // ... do truck specific things
            break;
            default:
            WriteLine("<unknown>");
            break;
            }
            }





            share|improve this answer





















            • 1





              Pattern matching is neat, but OOP was invented precisely to avoid this type of code.

              – Groo
              Nov 25 '18 at 21:23











            • Good point, actually. I just wanted to show that the values are not lost if you recover the real type from the common vehicle list.

              – Waescher
              Nov 25 '18 at 21:24











            • @Groo - "invented precisely to avoid this type of code" - What? No, it was invented to precisely allow this kind of code. Do you have a reference to avoiding it?

              – Enigmativity
              Nov 25 '18 at 21:39






            • 1





              @Enigmativity: I am not sure what you are referring to with "precisely allow". Polymorphism means abstracting the actual object type and hiding the actual implementation through its interface (which is violated in this example which knows specifics of each subclass). Single responsibility principle states that a class should have single reason to change (violated here, you will need to update each switch/case in your program when you add a Boat). This code is basically the school example for refactoring into OO code.

              – Groo
              Nov 25 '18 at 22:15











            • @Groo - OOP wasn't invented with the SOLID principles. They came along later. OOP was invented to allow polymorphism. When I said "precisely allow" I was referring to your line "invented precisely to avoid this type of code".

              – Enigmativity
              Nov 25 '18 at 22:19














            0












            0








            0







            If you have a List<A>, you can use it for each class of the type of A and all derived classes. Lets take it to the real world:



            If you have a definition Vehicle (that's your A). You could write a software for a car rental company which handles vehicles. They have all sorts for vehicles like one or more bikes (that's B) and one or more cars (that's C). Both are very different but both are vehicles.



            By using the abstraction of a Vehicle (A), you can store bikes and cars in the same context.



            So in a List<Vehicle>, you could store bikes, cars, trucks and all sort of movable stuff. However, the definition Vehicle will have the least common denominator like the kind of motor, the count of doors, etc. But you would (hopefully) not find truck-specific properties on that definition of vehicle which might not fit to others like a bike or a car.



            Tracking bikes and cars as vehicles does not strip of the fields at all. However, they are treated as vehicles, that's why you would not see the specific properties until you cast each vehicle to its real type. There are some approaches to this, I'd like to highlight Pattern Matching in C# 7 which makes it really easy by now.



            foreach (var v in vehicleList)
            {
            switch (v)
            {
            case Bike b:
            // ... do bike specific things
            break;
            case Car c:
            // ... do car specific things
            break;
            case Truck t:
            // ... do truck specific things
            break;
            default:
            WriteLine("<unknown>");
            break;
            }
            }





            share|improve this answer















            If you have a List<A>, you can use it for each class of the type of A and all derived classes. Lets take it to the real world:



            If you have a definition Vehicle (that's your A). You could write a software for a car rental company which handles vehicles. They have all sorts for vehicles like one or more bikes (that's B) and one or more cars (that's C). Both are very different but both are vehicles.



            By using the abstraction of a Vehicle (A), you can store bikes and cars in the same context.



            So in a List<Vehicle>, you could store bikes, cars, trucks and all sort of movable stuff. However, the definition Vehicle will have the least common denominator like the kind of motor, the count of doors, etc. But you would (hopefully) not find truck-specific properties on that definition of vehicle which might not fit to others like a bike or a car.



            Tracking bikes and cars as vehicles does not strip of the fields at all. However, they are treated as vehicles, that's why you would not see the specific properties until you cast each vehicle to its real type. There are some approaches to this, I'd like to highlight Pattern Matching in C# 7 which makes it really easy by now.



            foreach (var v in vehicleList)
            {
            switch (v)
            {
            case Bike b:
            // ... do bike specific things
            break;
            case Car c:
            // ... do car specific things
            break;
            case Truck t:
            // ... do truck specific things
            break;
            default:
            WriteLine("<unknown>");
            break;
            }
            }






            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Nov 25 '18 at 21:40

























            answered Nov 25 '18 at 21:22









            WaescherWaescher

            2,85431730




            2,85431730








            • 1





              Pattern matching is neat, but OOP was invented precisely to avoid this type of code.

              – Groo
              Nov 25 '18 at 21:23











            • Good point, actually. I just wanted to show that the values are not lost if you recover the real type from the common vehicle list.

              – Waescher
              Nov 25 '18 at 21:24











            • @Groo - "invented precisely to avoid this type of code" - What? No, it was invented to precisely allow this kind of code. Do you have a reference to avoiding it?

              – Enigmativity
              Nov 25 '18 at 21:39






            • 1





              @Enigmativity: I am not sure what you are referring to with "precisely allow". Polymorphism means abstracting the actual object type and hiding the actual implementation through its interface (which is violated in this example which knows specifics of each subclass). Single responsibility principle states that a class should have single reason to change (violated here, you will need to update each switch/case in your program when you add a Boat). This code is basically the school example for refactoring into OO code.

              – Groo
              Nov 25 '18 at 22:15











            • @Groo - OOP wasn't invented with the SOLID principles. They came along later. OOP was invented to allow polymorphism. When I said "precisely allow" I was referring to your line "invented precisely to avoid this type of code".

              – Enigmativity
              Nov 25 '18 at 22:19














            • 1





              Pattern matching is neat, but OOP was invented precisely to avoid this type of code.

              – Groo
              Nov 25 '18 at 21:23











            • Good point, actually. I just wanted to show that the values are not lost if you recover the real type from the common vehicle list.

              – Waescher
              Nov 25 '18 at 21:24











            • @Groo - "invented precisely to avoid this type of code" - What? No, it was invented to precisely allow this kind of code. Do you have a reference to avoiding it?

              – Enigmativity
              Nov 25 '18 at 21:39






            • 1





              @Enigmativity: I am not sure what you are referring to with "precisely allow". Polymorphism means abstracting the actual object type and hiding the actual implementation through its interface (which is violated in this example which knows specifics of each subclass). Single responsibility principle states that a class should have single reason to change (violated here, you will need to update each switch/case in your program when you add a Boat). This code is basically the school example for refactoring into OO code.

              – Groo
              Nov 25 '18 at 22:15











            • @Groo - OOP wasn't invented with the SOLID principles. They came along later. OOP was invented to allow polymorphism. When I said "precisely allow" I was referring to your line "invented precisely to avoid this type of code".

              – Enigmativity
              Nov 25 '18 at 22:19








            1




            1





            Pattern matching is neat, but OOP was invented precisely to avoid this type of code.

            – Groo
            Nov 25 '18 at 21:23





            Pattern matching is neat, but OOP was invented precisely to avoid this type of code.

            – Groo
            Nov 25 '18 at 21:23













            Good point, actually. I just wanted to show that the values are not lost if you recover the real type from the common vehicle list.

            – Waescher
            Nov 25 '18 at 21:24





            Good point, actually. I just wanted to show that the values are not lost if you recover the real type from the common vehicle list.

            – Waescher
            Nov 25 '18 at 21:24













            @Groo - "invented precisely to avoid this type of code" - What? No, it was invented to precisely allow this kind of code. Do you have a reference to avoiding it?

            – Enigmativity
            Nov 25 '18 at 21:39





            @Groo - "invented precisely to avoid this type of code" - What? No, it was invented to precisely allow this kind of code. Do you have a reference to avoiding it?

            – Enigmativity
            Nov 25 '18 at 21:39




            1




            1





            @Enigmativity: I am not sure what you are referring to with "precisely allow". Polymorphism means abstracting the actual object type and hiding the actual implementation through its interface (which is violated in this example which knows specifics of each subclass). Single responsibility principle states that a class should have single reason to change (violated here, you will need to update each switch/case in your program when you add a Boat). This code is basically the school example for refactoring into OO code.

            – Groo
            Nov 25 '18 at 22:15





            @Enigmativity: I am not sure what you are referring to with "precisely allow". Polymorphism means abstracting the actual object type and hiding the actual implementation through its interface (which is violated in this example which knows specifics of each subclass). Single responsibility principle states that a class should have single reason to change (violated here, you will need to update each switch/case in your program when you add a Boat). This code is basically the school example for refactoring into OO code.

            – Groo
            Nov 25 '18 at 22:15













            @Groo - OOP wasn't invented with the SOLID principles. They came along later. OOP was invented to allow polymorphism. When I said "precisely allow" I was referring to your line "invented precisely to avoid this type of code".

            – Enigmativity
            Nov 25 '18 at 22:19





            @Groo - OOP wasn't invented with the SOLID principles. They came along later. OOP was invented to allow polymorphism. When I said "precisely allow" I was referring to your line "invented precisely to avoid this type of code".

            – Enigmativity
            Nov 25 '18 at 22:19


















            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53471900%2fc-sharp-stacking-different-classes-in-the-same-list%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            404 Error Contact Form 7 ajax form submitting

            How to know if a Active Directory user can login interactively

            TypeError: fit_transform() missing 1 required positional argument: 'X'