50

I'm not sure if this is a strange thing to do or not, or if it is some how code smell...but I was wondering if there was a way (some sort of oop pattern would be nice) to "cast" a base type to a form of its derived type. I know this makes little sense as the derived type will have additional functionality that the parent doesn't offer which is in its self not fundamentally sound. But is there some way to do this? Here is a code example to so I can better explain what I"m asking.

public class SomeBaseClass {
    public string GetBaseClassName {get;set;}
    public bool BooleanEvaluator {get;set;}
}

public class SomeDerivedClass : SomeBaseClass {
    public void Insert(SqlConnection connection) {
          //...random connection stuff
          cmd.Parameters["IsItTrue"].Value = this.BooleanEvalutar;
          //...
    }
}

public static void Main(object[] args) {
    SomeBaseClass baseClass = new SomeBaseClass();
    SomeDerivedClass derClass = (SomeDerivedClass)baseClass; 
    derClass.Insert(new sqlConnection());
}

I know this seems goofy but is there any way to accomplish something of this sort?

Naser Asadi
  • 1,153
  • 18
  • 35
Adam Driscoll
  • 9,395
  • 9
  • 61
  • 104
  • 1
    The use of the term "cast" in this question is wrong. Casting imply that the object we cast is already an object of this type. For example : object o = 3; MethodWithIntegerParam((int)o); In your question baseClass isn't instantiate with derived class. So what you looking for is Conversion and not casting. – AXMIM May 07 '15 at 12:45

18 Answers18

30

Not soundly, in "managed" languages. This is downcasting, and there is no sane down way to handle it, for exactly the reason you described (subclasses provide more than base classes - where does this "more" come from?). If you really want a similar behaviour for a particular hierarchy, you could use constructors for derived types that will take the base type as a prototype.

One could build something with reflection that handled the simple cases (more specific types that have no addition state). In general, just redesign to avoid the problem.

Edit: Woops, can't write conversion operators between base/derived types. An oddity of Microsoft trying to "protect you" against yourself. Ah well, at least they're no where near as bad as Sun.

lomaxx
  • 113,627
  • 57
  • 144
  • 179
Adam Wright
  • 48,938
  • 12
  • 131
  • 152
  • You cant use casting/conversion operators for this case. – leppie Sep 23 '08 at 22:39
  • `Ah well, at least they're no where near as bad as Sun.` - how do you mean? Just out of curiosity; I don't know Java. (I know it's been 4 years.) – Konrad Morawski Aug 24 '12 at 21:02
  • 4
    @KonradMorawski I was referring to Java language features designed to ensure you write "good" code (where "good" is their opinion). My most hated being checked exceptions (so you *cannot* just ignore exceptions, ever). – Adam Wright Aug 25 '12 at 13:15
  • "Woops, can't write conversion operators between base/derived types." .Net allows this and it's possible to do using C#. See http://stackoverflow.com/a/15987692/1497385 – Ark-kun Apr 13 '13 at 12:20
19

Try composition instead of inheritance!

It seems to me like you'd be better off passing an instance of SomeBaseClass to the SomeDerivedClass (which will no longer derive base class, and should be renamed as such)

public class BooleanHolder{       
    public bool BooleanEvaluator {get;set;}
}

public class DatabaseInserter{
    BooleanHolder holder;

    public DatabaseInserter(BooleanHolder holder){
        this.holder = holder;
    }

    public void Insert(SqlConnection connection) {
          ...random connection stuff
          cmd.Parameters["IsItTrue"].Value = holder.BooleanEvalutar;
          ...
    }
}

public static void Main(object[] args) {
    BooleanHolder h = new BooleanHolder();
    DatabaseInserter derClass = new DatabaseInserter(h);
    derClass.Insert(new sqlConnection);
}

Check out http://www.javaworld.com/javaworld/jw-11-1998/jw-11-techniques.html (page 3):

Code reuse via composition Composition provides an alternative way for Apple to reuse Fruit's implementation of peel(). Instead of extending Fruit, Apple can hold a reference to a Fruit instance and define its own peel() method that simply invokes peel() on the Fruit.

Rob Fonseca-Ensor
  • 15,510
  • 44
  • 57
  • 16
    Though I do favor composition over inheritance, the idea that "Apple has a fruit" rather than "Apple is a fruit" is about the worst example I've ever seen for it. If Apple defines it's own Peel method, then it's no longer substitutable for Fruit - which kind of borks the whole concept of Fruit. – Mark Brackett Sep 24 '08 at 23:10
  • 1
    Rather than "Apple has fruit" you could read it as "Apple has the properties of being a fruit", which sounds much better and is also in fact more accurate than "Apple is fruit". – intrepidis Dec 19 '14 at 21:58
  • I'd argue that "the property of being a fruit" would neither be composition nor inheritance but the implementation of an interface :) – HaMster Dec 06 '17 at 10:45
16

Personally I don't think it's worth the hassle of using Inheritance in this case. Instead just pass the base class instance in in the constructor and access it through a member variable.

private class ExtendedClass //: BaseClass - like to inherit but can't
{
    public readonly BaseClass bc = null;
    public ExtendedClass(BaseClass b)
    {
        this.bc = b;
    }

    public int ExtendedProperty
    {
        get
        {
        }
    }
}
hichris123
  • 10,145
  • 15
  • 56
  • 70
Rob Sedgwick
  • 4,342
  • 6
  • 50
  • 87
  • I found this very useful, especially when transforming a base class list into another list with more functionality in each list item. – Ben Winding Dec 16 '15 at 11:41
  • But in this case it is impossible to call base class methods, due to ExtendedClass don't have them at all –  May 06 '16 at 08:53
  • 1
    Yes you can: extendedObject.BaseClass.BaseClassMethod(args) – Rob Sedgwick May 06 '16 at 09:31
  • This looks like an almost "Decorator" pattern, which would work in this case and worth googling! Design patterns have most of the answers!! – dreadeddev May 10 '17 at 09:14
9

Downcasting makes sense, if you have an Object of derived class but it's referenced by a reference of base class type and for some reason You want it back to be referenced by a derived class type reference. In other words You can downcast to reverse the effect of previous upcasting. But You can't have an object of base class referenced by a reference of a derived class type.

Maciej Hehl
  • 7,895
  • 1
  • 22
  • 23
  • Its interesting that when you "reverse" the upcast, all the "extra" derived information is accessible again. Clearly, its retained on the memory heap in some way. – Chris Johnson Oct 10 '13 at 09:35
  • I've been reading around this issue. The reason that the information is retained on that object is that the object itself isn't changed when you upcast it, only the reference to it. And RE this answer, it seems like a perfectly legit reason to downcast. Especially when dealing with SOA. – Craig Brett Apr 09 '14 at 13:18
7

I'm not saying I recommend this. But you could turn base class into JSON string and then convert it to the derived class.

SomeDerivedClass layer = JsonConvert.DeserializeObject<SomeDerivedClass>(JsonConvert.SerializeObject(BaseClassObject));
Donny V.
  • 22,248
  • 13
  • 65
  • 79
5

No, this is not possible. In a managed language like C#, it just won't work. The runtime won't allow it, even if the compiler lets it through.

You said yourself that this seems goofy:

SomeBaseClass class = new SomeBaseClass();
SomeDerivedClass derClass = (SomeDerivedClass)class; 

So ask yourself, is class actually an instance of SomeDerivedClass? No, so the conversion makes no sense. If you need to convert SomeBaseClass to SomeDerivedClass, then you should provide some kind of conversion, either a constructor or a conversion method.

It sounds as if your class hierarchy needs some work, though. In general, it shouldn't be possible to convert a base class instance into a derived class instance. There should generally be data and/or functionality that do not apply to the base class. If the derived class functionality applies to all instances of the base class, then it should either be rolled up into the base class or pulled into a new class that is not part of the base class hierarchy.

Derek Park
  • 45,824
  • 15
  • 58
  • 76
  • "No, this is not possible. In a managed language like C#, it just won't work." .Net allows this and it's possible to do using C#. See http://stackoverflow.com/a/15987692/1497385 – Ark-kun Apr 13 '13 at 12:18
5

C# language doesn't permit such operators, but you can still write them and they work:

[System.Runtime.CompilerServices.SpecialName]
public static Derived op_Implicit(Base a) { ... }

[System.Runtime.CompilerServices.SpecialName]
public static Derived op_Explicit(Base a) { ... }
Ark-kun
  • 6,358
  • 2
  • 34
  • 70
  • how the implicit op would work if you assign List = List ? – Boppity Bop Aug 12 '16 at 16:07
  • @BoppityBop it would work the same as `List = List` or `List = List` - it would not work. You may create your own collection with some implicit conversion operators though. – Ark-kun Aug 12 '16 at 23:02
  • just to be clear. u r saying that `op_Implicit` as per your solution *will not be called* when base/derived are in a generic collection. right? – Boppity Bop Aug 15 '16 at 11:48
  • @BoppityBop Yes. Operators are static. There is not even operator inheritance. Much less "generic class element type operator inheritance". – Ark-kun Aug 18 '16 at 07:45
1

Yes - this is a code smell, and pretty much nails down the fact that your inheritance chain is broken.

My guess (from the limited sample) is that you'd rather have DerivedClass operate on an instance of SomeBaseClass - so that "DerivedClass has a SomeBaseClass", rather than "DerivedClass is a SomeBaseClass". This is known as "favor composition over inheritance".

Mark Brackett
  • 84,552
  • 17
  • 108
  • 152
1

Have you thought about an interface that what is currently your base class and your derived class both would implement? I don't know the specifics of why you're implementing this way but it might work.

marr75
  • 5,666
  • 1
  • 27
  • 41
1

As others have noted, the casting you suggest is not really possible. Would it maybe be a case where the Decorator pattern(Head First extract) can be introduced?

Boris Callens
  • 90,659
  • 85
  • 207
  • 305
  • .Net allows this and it's possible to do using C#. See http://stackoverflow.com/a/15987692/1497385 – Ark-kun Apr 13 '13 at 12:19
0

That cannot work. Go look at the help page linked by the compile error.

The best solution is to use factory methods here.

hichris123
  • 10,145
  • 15
  • 56
  • 70
leppie
  • 115,091
  • 17
  • 196
  • 297
0

This is called downcasting and Seldaek's suggestion to use the "safe" version is sound.

Here's a pretty decent description with code samples.

Ben Hoffstein
  • 102,129
  • 8
  • 104
  • 120
0

This is not possible because how are you going to get the "extra" that the derived class has. How would the compiler know that you mean derivedClass1 and not derivedClass2 when you instantiate it?

I think what you are really looking for is the factory pattern or similar so you can instantiate objects without really knowing the explicit type that's being instantiate. In your example, having the "Insert" method would be an interface that instance the factory returns implements.

Laplie Anderson
  • 6,345
  • 4
  • 33
  • 37
0

I dont know why no one has said this and i may have miss something but you can use the as keyword and if you need to do an if statement use if.

SomeDerivedClass derClass = class as SomeDerivedClass; //derClass is null if it isnt SomeDerivedClass
if(class is SomeDerivedClass)
    ;

-edit- I asked this question long ago

Community
  • 1
  • 1
0

As many answers have pointed out, you can't downcast which makes total sense.

However, in your case, SomeDerivedClass doesn't have properties that will be 'missing'. So you could create an extension method like this:

public static T ToDerived<T>(this SomeBaseClass baseClass) 
    where T:SomeBaseClass, new()
{
    return new T()
    {
        BooleanEvaluator = baseClass.BooleanEvaluator,
        GetBaseClassName = baseClass.GetBaseClassName
    };
}

So you aren't casting, just converting:

SomeBaseClass b = new SomeBaseClass();
SomeDerivedClass c = b.ToDerived<SomeDerivedClass>();

This only really works if all of the data in the base class is in the form of readable and writable properties.

hichris123
  • 10,145
  • 15
  • 56
  • 70
johnnycardy
  • 3,049
  • 1
  • 17
  • 27
0

C# doesn't support upcasting natively. However, there is a simple trick to achieve it considering a few limitations:

  1. The classes must be POCO/DTOs without logic associated to their properties.
  2. The classes can exists on their own with default values for their properties.

The easiest and fastest way to do it is via serialization. Since the base class and the derived classes share the common properties defined in the base class - than at least for those properties we can move the values from the base class to the more derived class.


public static TCastType To<TFromType, TCastType>(this TFromType from)
{
  var options = new System.Text.Json.JsonSrializerOptions();
  var json = JsonSerializer.Serialize<TFromType>(from, options);

  var castType = JsonSerializer.Deserialize<TCastType>(json, options)
  return castType;
}

So in effect we serialize the base class to json and then deserialize the json in the more derived class. The only caveat is that properties in the derived class that are not in the base class will be initialized with default values.

This also works when you want to change between two derived types of the same base class. In that scenario the common properties of the two types will be initialized from the deserialization routine, and the ones that do not match the destination type will simply be ommited.

bleepzter
  • 9,607
  • 11
  • 41
  • 64
0

I've recently been in the need of extending a simple DTO with a derived type in order to put some more properties on it. I then wanted to reuse some conversion logic I had, from internal database types to the DTOs.

The way I solved it was by enforcing an empty constructor on the DTO classes, using it like this:

class InternalDbType {
    public string Name { get; set; }
    public DateTime Date { get; set; }
    // Many more properties here...
}

class SimpleDTO {
    public string Name { get; set; }
    // Many more properties here...
}

class ComplexDTO : SimpleDTO {
    public string Date { get; set; }
}

static class InternalDbTypeExtensions {
    public static TDto ToDto<TDto>(this InternalDbType obj) where TDto : SimpleDTO, new() {
        var dto = new TDto {
            Name = obj.Name
        }
    }
}

I can then reuse the conversion logic from the simple DTO when converting to the complex one. Of course, I will have to fill in the properties of the complex type in some other way, but with many, many properties of the simple DTO, this really simplifies things IMO.

lbergnehr
  • 1,578
  • 11
  • 15
-1

C++ handles it using a constructor. C++ Typecasting. It seems like an oversight to me. Many of you have brought up the issue of what would the process do with the extra properties. I would answer, what does the compiler do when it creates the derived class when the programmer does not set the properties? I have handled this situation similar to C++. I create a constructor that takes the base class then manually set the properties in the constructor. This is definitely preferable to setting a variable in the derived class and breaking the inheritance. I would also choose it over a factory method because I think the resulting code would be cleaner looking.

Michael Dillon
  • 1,037
  • 6
  • 16