8

I am extending the existing .NET framework class by deriving it. How do I convert an object of base type to derived type?

public class Results { //Framework methods }

public class MyResults : Results { //Nothing here }

//I call the framework method

public static MyResults GetResults()
{
    Results results = new Results();
    //Results results = new MyResults(); //tried this as well.

    results = CallFrameworkMethod();

    return (MyResults)results; //Throws runtime exception
}

I understand that this happens as I am trying to cast a base type to a derived type and if derived type has additional properties, then the memory is not allocated. When I do add the additional properties, I don't care if they are initialized to null.

How do I do this without doing a manual copy?

Nick
  • 7,475
  • 18
  • 77
  • 128
  • 1
    Instead of extending the type can you just create an Extension method? – Chris Haas Mar 25 '10 at 21:52
  • This is a good idea. With Extension methods, I can attach new methods. I can't really add additional properties/variables to the type. – Nick Mar 25 '10 at 22:06
  • That seems like a lot of work to avoid writing a simple copy constructor. I know in a lot of cases that isn't possible, but it seems like a possible solution in this case. – overslacked Mar 25 '10 at 22:10
  • @overslacked - How would the copy constructor look? Can you give me some pointers? – Nick Mar 26 '10 at 14:28

6 Answers6

12

You can't. If results doesn't refer to a MyResults (e.g. if CallFrameworkMethod returns a base Results instance), then casting won't make it so: you'll need to create a new MyResults, based on the existing non-MyResults. Casting is about changing the compile-time type of the reference, not about changing the concrete type of the referenced object.

You can use tools such as Reflection or AutoMapper to help with the initialisation of the new MyResults object -- but a new MyResults object there must be, because you cannot tell a base Results object to become a MyResults object.

itowlson
  • 73,686
  • 17
  • 161
  • 157
  • Is this have to do with variance/covariance? I am on .NET 4.0 and i know that they did something for variance/covariance. Any idea? – Nick Mar 25 '10 at 21:49
  • No, C# 4.0 variance is to do with when you're using base/derived types as type parameters for generic interfaces or delegates; and you don't have any generic interfaces or delegates here. Your problem is more fundamental: it's about the concrete type of the object. A Results object simply *is not* an instance of the MyResults type. If CallFrameworkMethod returns an (actual) Results, references to that object *cannot* be cast to MyResults because the object *is not* a MyResults. The only way around this is to change CallFrameworkMethod to return a MyResults, or to create a new MyResults. – itowlson Mar 25 '10 at 22:01
1

How about:

...
MyResults results  = new MyResults();
...

And you maybe also need to create a COnstructor in your MyResults class:

public class MyResults : Results
{
    public MyResults() : base() {}
}

What exactly means "nothing here"?

EDIT

 results = (CallFrameworkMethod() as MyResults);

It doesnt throw the exception, but if it would be useful for you - it depends on what you would like to do further...

Gacek
  • 10,184
  • 9
  • 54
  • 87
  • "nothing here" as in literally nothing. For now, I have inherited from the base type with the intention of adding new properties in the future – Nick Mar 25 '10 at 21:36
  • I see. I Edited my answer - please check new solution. – Gacek Mar 25 '10 at 21:43
  • @Gacek - Using the as keyword does not throw an exception but MyResult object is null although the CallFrameworkMethod returns a non null object. – Nick Mar 25 '10 at 21:45
  • Regarding your edit: if CallFrameworkMethod is returning a `Results` rather than a `MyResults` then your edit will just set `results` to null. The cast still fails, but the `as` operator indicates this by returning null rather than throwing an exception. – itowlson Mar 25 '10 at 21:45
  • Is there in the Results class a constructor, that allows to create one object basing on other? Something like `Results(Results referenceObject)`? If so, you can implement similar constructor in your class (by deriving the original constructor) and then call it like that: `var results = new MyResults(CallFrameworkMethod());` – Gacek Mar 25 '10 at 21:50
  • Unfortunately no. I looked at the Results implementation by the framework and it does not have this. – Nick Mar 25 '10 at 22:04
1
Results results = new MyResults();
   ...

return (MyResults)results;

should work. If not, then the problem is somewhere alse.

Machta
  • 1,656
  • 2
  • 16
  • 28
  • 1
    No, because he then overwrites it with the return value of CallFrameworkMethod -- which is presumably returning something other than a MyResults, or the cast would succeed. – itowlson Mar 25 '10 at 21:33
  • He makes an instance of the MyResult class and then calls the CallFrameworkMethod method which assigns to the results object some other instance which cannot be casted. – Machta Mar 25 '10 at 21:40
1

No, you can't avoid copying the content into a instance of the derived type. Well, if you can change CallFrameworkMethod to be a generic method, and MyResults has a zero-argument constructor, then CallFrameworkMethod could create a new instance of your derived type directly, then use only the members of the parent type.

But probably you'll have to end up copying to a new object. Remember that this copying code can certainly be reused in another method, you don't have to rewrite it everywhere you need it.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • How would the copy constructor look? Can you give me some pointers? – Nick Mar 26 '10 at 14:09
  • C# doesn't have "copy constructors". But you can certainly write a reusable method that accepts the base class and returns an instance of the derived class, with all the base class members copied. Or were you asking about the generic idea? – Ben Voigt Mar 26 '10 at 16:57
1

As earlier answers have said, you need to instantiate a new instance of MyResults then copy the properties over from your Results object. You asked what a "copy constructor" was - it is just a constructor that takes an object and uses it to populate the object being constructed. For example:

    public class Results
    {
        public string SampleProperty1 { get; set; }
        public string SampleProperty2 { get; set; }
    }

    public class MyResults : Results
    {
        public MyResults(Results results)
        {
            SampleProperty1 = results.SampleProperty1;
            SampleProperty2 = results.SampleProperty2;
        }
    }

A copy constructor is usually more convenient, readable and reusable than using code like this:

MyResults myResults = new MyResults
{
    SampleProperty1 = results.SampleProperty1,
    SampleProperty2 = results.SampleProperty2
};

If there are lots of properties and/or you are making lots of changes to the class you could use reflection (e.g. C# Using Reflection to copy base class properties ) or a tool such as AutoMapper ( http://automapper.codeplex.com ) to copy the properties. But often that can be overkill.

Community
  • 1
  • 1
Jonathan Moffatt
  • 13,309
  • 8
  • 51
  • 49
0

To downcast an Object into its derived class(es), The Object must be born in it derived class. For example: I have a simple class called Shape here is the code for Shape class

public class Shape{
     public void draw(){}
}

and then I have an other class named Circle as follows:

public class Circle:Shape{
      public void drawCircle(){}
}

Now if I create an object of Super class like

Shape noShape = new Shape();

And if try to downcast this noShape object to Circle object like this

Circle circle = (Circle) noShape; 

it will generate an exception. This is because circle was never born as Shape To perform this down-casting functionality, noShape must be born as Circle object. Which can be done as this:

Circle initialShape = new Circle();

Now you can simply upcast this initialShape object to Shape object. like this

Shape upcastedObject = initialShape;

Now you can Down-cast the object upcastedObject to its derived class like

Circle derivedCircle = (Circle) upcastedObject;

Now the derivedCircle object will behave like a Circle object. Because it was born as Circle. I am using the word BORN so keep this in mind. The reason of doing so or the use-case of doing so is up to your requirement.

majid bhatti
  • 83
  • 12