0

Consider the following situation:

  • A base class named Result.
  • A derived class of Result named RBTResult.
  • A derived class of RBTResult named ResultNL

    class Result {}
    
    class RBTResult : Result {}
    
    class ResultNL : RBTResult {}
    

There's a List of 'Result' which holds concrete instances of RBTResult. So far so good.

    static void Main(string[] args) {
        List<Result> results = new List<Result> {
          new RBTResult(), 
          new RBTResult() 
        };

        append<ResultNL>(results);
    }

We pass that list to a generic function append<T>() where the generic type T is ResultNL.

In append there is a loop casting every item in the list to the generic type argument but there an InvalidCastException is thrown every time.

    static void append<T>(List<Result> res) where T : Result
    {
        List<Result> l = new List<Result>();
        foreach (var r in res)
        {
            try
            {
                _ = (T)r;
                l.Add(r);
            }
            catch (InvalidCastException e) { }
        }
    }

I would say it should be possible to cast from RBTResult to T (ResultNL) because it is a derived class, but it doesnt.

Why is that? How to make this work?

Serve Laurijssen
  • 9,266
  • 5
  • 45
  • 98
  • 1
    Its saving you from making a mistake, and is just generally trying to be type safe – TheGeneral Jun 11 '19 at 10:06
  • 2
    What´s the point of a **generic** method when you cast to a **specific** type? When your method does different things based on the type, it should probably be different methods. – MakePeaceGreatAgain Jun 11 '19 at 10:06
  • 1
    As an aside - there is a good chance you're using inheritance wrong here. – Jamiec Jun 11 '19 at 10:12
  • 1) you should have made `Result` an `abstract` class. That would have prevented a few things and fixed a few problems along the way 2) what makes you think you can cast an `Apple` to an `Octopus`? They might both be `Food` but sadly they lack metamorphing skills, even if the octopus can change colour –  Jun 11 '19 at 10:17
  • 1
    And to add a 3rd point: don´t rely on exceptions to check if an instance is of a certain type. Instead use the `as` or `is` operators. But that´s going to be pointless, as you can´t cast to a derived type anyway. – MakePeaceGreatAgain Jun 11 '19 at 10:25
  • Although this is marked as duplicate, OP is asking specifically why... Inheritance means you can always cast back up the tree to the parent, or any parent of the parent, the inheritance contract guarantees that each child will possess or implement the same structure of the parent, but each child can evolve the implementation adding more functionality. The child is always a sub-set of the parent, so the child can always be cast as the parent type, but the child may have additional functionality that the parent does not provide, so a parent cannot be cast as the child. – Chris Schaller Jun 11 '19 at 10:50
  • The term "type safety" tends to be a bit too abstract. This is really about memory safety. If that cast would succeed then you could access fields of the ResultNL class that don't actually exist. You'd read garbage, get an AccessViolationException only when you're lucky, cause very nasty memory corruption when you assign them since the assignment will overwrite memory that belongs to a different object. – Hans Passant Jun 11 '19 at 12:39

0 Answers0