locked
Explicit Conversion of Base Class to Derived Class

    Question

  • I did a search on the subject, and the answer I found said that converting a base class to a derived class is not possible. I find this answer to be unsatisfactory, and I wish to make sure that it is indeed the correct answer.

     

    I am writing some code (obviously), and in my code, I have a base class and an inherited class of that base class. There are times I wish to convert the base class to the inherited class. According to section 13.2.3 of the C# specification, this is possible:

     

    "From any class-type S to any class-type T, provided S is a base class of T."

     

    There's also evidence that in the .NET Framework that it's possible (converting WebRequest to HttpWebRequest and Control to TextBox). So why is it I get a runtime error of InvalidCastException when I attempt to explicitly cast an instance of my base class to an instance of a derived class of that base class?

     

     

    Friday, May 11, 2007 3:22 PM

Answers

  •  Fanon wrote:

    I did a search on the subject, and the answer I found said that converting a base class to a derived class is not possible. I find this answer to be unsatisfactory, and I wish to make sure that it is indeed the correct answer.

     

    I am writing some code (obviously), and in my code, I have a base class and an inherited class of that base class. There are times I wish to convert the base class to the inherited class. According to section 13.2.3 of the C# specification, this is possible:

     

    "From any class-type S to any class-type T, provided S is a base class of T."

     

    There's also evidence that in the .NET Framework that it's possible (converting WebRequest to HttpWebRequest and Control to TextBox). So why is it I get a runtime error of InvalidCastException when I attempt to explicitly cast an instance of my base class to an instance of a derived class of that base class?

     

     

    You can't convert an instance of a base class to a derived class without some sort of conversion operator.  If you have a instance of a derived class stored as a base class variable you can cast as a derived class.  For example:

    Code Snippet

    Base base = new Derived();

    Derived derived = base as Derived;

     

     

    Friday, May 11, 2007 5:08 PM
    Moderator
  • I'm checking into why that specific conversion is an error.  I think it might be a bug; but, I'll confirm.  If it's a bug there probably won't be a fix for it until .NET 3.x.

     

    So, you'll have to write a non-operator method, e.g.:

    Code Snippet
      internal static Derived FromBase(Base b)
      {
       Derived result = b as Derived;
       if(null == result)
       {
        result = new Derived(b);
       }
       return result;
      }

     

    Note that since a reference to Derived can be cast to Base this method first checks to see if the object is already a Derived object; if not it creates a new one.

    Friday, May 11, 2007 8:13 PM
    Moderator

All replies

  • There is a difference between (the two conxepts), only one of them is possible.

    It is possible to store a child as it's parent (ie TextBox can be stored in Control). This is fundamental, you can see it in Exceptions most clearly as you can catch Exception and catch everything that has some inheritance line to Exception. You can store a derived class into a base class object and then (cast) back to the derived class. However you couldn't store a TextBox in a Control object then cast it to a Label (also derived from Control).

    Converting from base to derived (parent to child, or part to product) is impossible to do "directly". It would be akin to being able to convert from a molecule from an atom object. Molecule is a "derived" class from atom (or let's just say it is). However, Molecule has more information than what atom provides, how do you deal with this? The problem is that derived classes have knowledge of their base but the base has no knowledge of their derived classes.

    [edit]I originally used boxing, it was the wrong terminology. Let's try not to confuse anyone with poorly worded replies being left.[/edit]
    Friday, May 11, 2007 4:55 PM
  •  IsshouFuuraibou wrote:
    This is called boxing and unboxing. You can always store into a base class and then unbox out to the derived class.
    No, boxing and unboxing is the packaging and unpackaging of value types as reference types.  This is due to Object being a reference type.

    [edit]see http://msdn2.microsoft.com/en-us/library/aa691157(VS.71).aspx [/edit]

    Friday, May 11, 2007 5:03 PM
    Moderator
  •  Fanon wrote:

    I did a search on the subject, and the answer I found said that converting a base class to a derived class is not possible. I find this answer to be unsatisfactory, and I wish to make sure that it is indeed the correct answer.

     

    I am writing some code (obviously), and in my code, I have a base class and an inherited class of that base class. There are times I wish to convert the base class to the inherited class. According to section 13.2.3 of the C# specification, this is possible:

     

    "From any class-type S to any class-type T, provided S is a base class of T."

     

    There's also evidence that in the .NET Framework that it's possible (converting WebRequest to HttpWebRequest and Control to TextBox). So why is it I get a runtime error of InvalidCastException when I attempt to explicitly cast an instance of my base class to an instance of a derived class of that base class?

     

     

    You can't convert an instance of a base class to a derived class without some sort of conversion operator.  If you have a instance of a derived class stored as a base class variable you can cast as a derived class.  For example:

    Code Snippet

    Base base = new Derived();

    Derived derived = base as Derived;

     

     

    Friday, May 11, 2007 5:08 PM
    Moderator
  • thanks for clarifying that, I was sure I was using the wrong wording...

    now is there a wording for storing a derived class stored as a base class variable, or is that the only description of it? I thought there was some terminology for that.
    Friday, May 11, 2007 5:15 PM
  •  IsshouFuuraibou wrote:
    thanks for clarifying that, I was sure I was using the wrong wording...

    now is there a wording for storing a derived class stored as a base class variable, or is that the only description of it? I thought there was some terminology for that.
    I consider it part of inheritance.  Depending on the context, polymorphic may apply.
    Friday, May 11, 2007 5:30 PM
    Moderator
  •  Peter Ritchie wrote:
    You can't convert an instance of a base class to a derived class without some sort of conversion operator.  If you have a instance of a derived class stored as a base class variable you can cast as a derived class.  For example:

    Code Snippet

    Base base = new Derived();

    Derived derived = base as Derived;

     

     

    Thank you for that information. I did not know you could program specific operators. I did a quick search and found I can program my own implicit and/or explicit conversion operators.  Thank you so much!

    Friday, May 11, 2007 6:52 PM
  • *sigh*

     

    So I write an explicit operator, and now I get a compile error saying "User-defined conversions to values of a base class are not allowed; you do not need such an operator". Well apparently I do because I can't convert it!

     

    Here's my code:

     

    Code Snippet

    public DerivedClass(BaseClass b) {

        //code to do the conversion

    }

     

    public static explicit operator DerivedClass(BaseClass b) {

        DerivedClass temp = new DerivedClass(b);

     

        return temp;

    }

     

     

    Friday, May 11, 2007 7:35 PM
  • I'm checking into why that specific conversion is an error.  I think it might be a bug; but, I'll confirm.  If it's a bug there probably won't be a fix for it until .NET 3.x.

     

    So, you'll have to write a non-operator method, e.g.:

    Code Snippet
      internal static Derived FromBase(Base b)
      {
       Derived result = b as Derived;
       if(null == result)
       {
        result = new Derived(b);
       }
       return result;
      }

     

    Note that since a reference to Derived can be cast to Base this method first checks to see if the object is already a Derived object; if not it creates a new one.

    Friday, May 11, 2007 8:13 PM
    Moderator
  • That is what I have resorted to to make the code work, although your method is more complete (checking to see if the object was cast to its base first).

     

    Thanks again, Mr. Ritchie.

    Friday, May 11, 2007 8:23 PM
  • Okay, found the official word from Microsoft: http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=142939&SiteID=1

     

    Looks like you're stuck writing a non-operator method.

    Friday, May 11, 2007 8:35 PM
    Moderator
  • Hi,

    i solved the problem using reflection:

    class Base
    {
          private string title;
          public string Title
          {
             get...
             set..
          }

          public CopyTo(ref Object target)
         {
                Type sourceType = this.GetType();
                Type destinationType = destination.GetType();

                foreach (PropertyInfo sourceProperty in sourceType.GetProperties())
                {
                    PropertyInfo destinationProperty = destinationType.GetProperty(sourceProperty.Name);
                    if (destinationProperty != null)
                    {
                        destinationProperty.SetValue(destination, sourceProperty.GetValue(this, null), null);
                    }
               }
         }
    }

    class Inherited : Base
    {
           //Inherits Title from base
           ...
    }


    main()
    {
           Base baseObject = new Base();
           Inherited inheritedObject = new Inherited();
           Object obj = (Object)inheritedObject;

          baseObject.Title = "Hello";
          baseObject.CopyTo(ref obj);
        
          System.Console.WriteLine(inheritedObject.Title);
      
    }

    -------------------------------------------------------
    Function CopyTo will copy values from source class to destination for properties with same name in source and destination.
    Hope this helps,
    Regards



    Thursday, July 12, 2007 1:05 PM
  • This is no "correct" solution in terms of class design. I do not advocate this to anyone. It does e.g. not check the type of the property nor is it anyhow performant.

    It has its sense that there is no easy way to cast a base class to a concret class or to a sibling (which would be the same as casting one sibling to its base and then to another concret implementation of the base - it's sibling).

    The objects are not compatible and just copying the properties doesn't make them really compatible.

     

    If you know that they are compatible, you can create a new method which converts them (this method could also be an explicit casting operator), but you should not provide a general-purpose solution because ther is no such general-purpose solution also the "solution" provided by Samodaje may work by some very rare problems but there will always be a better, more performant and nicer alternative to it.

    Thursday, July 12, 2007 4:50 PM
  •  This method is effective, however, keep in mind that if you have any properties with setters that do more than just set a private variable you may encounter an exception during the copy.

    In my specific case, I have an exception as a property of my base object.  In the setter, I have a method which automatically logs it to a database.  This caused the copy to blow up, forcing me to move the logging method elsewhere.

    Hope this helps!
    Tuesday, June 24, 2008 9:45 PM
  • Hi Peter,

    I implemented the code above to cast a base class to a child class but the values of the child class are picked up without any change. It almost acts as if we would create another instance of the child class (here we are creating a reference). Here is my code, would love to know your input on this. However, creating a child class constructor with base class as a parameter works, but I am not sure if technically that could be called casting, again, it is another reference created.

    NOTE: when the second line of the above code snippet is executed, I got NullExceptionError, so I had to try the way I did in Approach 2.

     

    public class ParentClass

            {

                public int A;

     

                public ParentClass()

                {

                    A = 10;

                }

     

                public virtual void vDisplay()

                {

                    Console.WriteLine("Parent Class A value : " + A.ToString());

                }

            }

     

            public class ChildClass : ParentClass

            {

                public int B;

     

                public override void vDisplay()

                {

                    base.vDisplay();

                    Console.WriteLine("Child Class B value : " + B.ToString ());

                }

     

                public ChildClass()

                {

                    B = 50;

                    base.A = 45;

                }

     

                public ChildClass(ParentClass rhs)

                {

                    B = rhs.A;

                }

     

            }

     

            static void Main()

            {

     

                // Child class to parent class casting

                ParentClass objP = new ChildClass();

                objP.vDisplay();

     

                // Parent Class to child class casting

                // Approach 1 --> Child Constructor Overload

                ParentClass objP1 = new ParentClass();

                ChildClass objC = new ChildClass(objP1);

                objC.vDisplay();

     

                // Approach 2 -->

                ParentClass objP2 = new ChildClass();

                ChildClass objC1 = objP2 as ChildClass;

                objC1.vDisplay();

     

                return;

            }

     

    Output:

    Parent Class A Value: 45

    Child Class B Value: 50

     

    After Approach 1 -

    Parent Class A Value: 10

    Child Class B Value: 10

     

    After Approach 2 -

    Parent Class A Value: 45

    Child Class B Value: 50


    Any help with this concept would be appreciated, in C++ dynamic_cast<> does the trick but I am confused with this one.


    Wednesday, July 14, 2010 11:26 PM
  • The C++ statement

    ChildClass* objC1 = dynamic_cast<ChildClass*>(objP2);

    does exactly the same thing as the C# statement

    ChildClass objC1 = objP2 as ChildClass;

     

    What did you expect the output to be?

    Thursday, July 15, 2010 12:29 AM
  • Let me explain why can't you explicity convert a base class to derived class.

    say i have a base class with 2 virtual methods m1 and m2, on derived class you'll ovverride these methods and apart from the define a net new method m3.

    Now say i make an object of base class, assign it to object of type derived class (explicit conversion, no compiletime error). Invoke m3 on derived object which is not valid as pointer of your object is still at base class.

    Thursday, June 23, 2011 7:26 PM
  • The section in the spec to which you refer is actually 6.2.4.  The conversion type you cited is an explicit reference conversion, which according to that section are "... those conversions between reference-types that require run-time checks to ensure they are correct."  Since the compiler cannot tell whether a base class S reference is NOT a subclass T reference, it assumes the explicit cast MAY be possible.  However, the lack of a compiler error does not indicate you will avoid a runtime 'Invalid Cast' error.

    For example, the following code will compile fine but will fail at runtime:

      Baseclass baseRef = new Baseclass();
      Subclass derivedRef = (Subclass) baseRef;

    The second line of the above example will fail at run-time, since in this case the expression "baseRef is Subclass" cannot be evaluated (i.e. baseRef is NOT actually type Subclass).  However, the following code will both compile and run fine:

      Baseclass baseRef = new Subclass();
      Subclass derivedRef = (Subclass) baseRef;

    This last example works at runtime because baseRef, although it is a Baseclass reference, actually contains a Subclass reference.


    Mark Jones



    • Edited by wmarkjones Tuesday, July 10, 2012 4:57 PM Removed superfluous phrase
    Tuesday, July 10, 2012 4:51 PM