views:

421

answers:

7

I have this simple structure: 1 parent, and two different childs.

public class Parent{}

public class ChildA : Parent{}

public class ChildB : Parent{}

I have an object objA of type ChildA, which I want to cast to ChildB. My naive approach says:

ChildA objA = new ChildA();

ChildB objB = (ChildB)objA;

But this is not directly possible - why? Is this because I need to implement some functions or because my naive approach is wrong?

Regards, Casper

+7  A: 

It's not possible because the object objA refers to is not a ChildB. To put it another way, here's an example of what you're trying to do:

 string x = "hi";
 FileStream y = (FileStream) x;

They both have a common parent - System.Object - but they're completely different classes. What would you expect to happen if you tried to read from y?

Suppose your ChildB type has some field which is specific to that type - what would you expect that field's value to be after casting objA?

Why do you want to pretend that a ChildA is actually a ChildB? Could you maybe add a method in the parent class which does what you want? Add a method in ChildA like this:

ChildB ToChildB()

to perform an appropriate conversion?

Jon Skeet
Well, to answer some of your questions: My idea by casting ChildA to ChildB is, that the common variables would survive and unassigned variables set to Null or the like. And this is exactly what I wanted, but due to your answer, I have chosen a conversion method instead.
Chau
@Chau: Your supposition would have been hugely unsafe - what if those variables had been required to make it a valid object? The conversion approach should be fine :)
Jon Skeet
@Jon: I'm sure you are perfectly right, but in my ideal world it would have worked just fine =)
Chau
Why don't you combine the properties that are shared between childA and childB into a class from which both inherit. That way you could `ChildB childB = childA as subChild;` Correct me if I'm wrong please Jon :)
Peter
@Peter: In this case, pushing them just into Parent. Yes, that's a preferable approach.
Jon Skeet
+2  A: 

You can't because ChildA is not a ChildB (you can only upcast from ChildA or ChildB to Parent, or downcast from Parent to ChildB or ChildA, there's no such thing as sidecasting in C#)

If you want to make the cast possible (a questionable endeavor, but well) you should implement an cast operator from ChildA to ChildB.

Yann Schwartz
Downcasting doesn't work either. Suppose you have:Parent p = new Parent();ChildA a = (ChildA)p;ORParent p = new ChildA(); ChildB b = (ChildB)p; You wouldn't expect that to work!
Chris Dunaway
Yep, it would fail at runtime, but it would compile.
Yann Schwartz
A: 

objA is NOT of type ChildB even if both are "children" from class Parent.

astander
A: 

What you're trying to do won't work.

You can only case objA to it's base class (Parent) or to any common interface that ChildA and ChildB might implement.

Imagine, for a moment, that ChildB defined a method called Foo. How would your instance of objA deal with someone calling Foo? Clearly it couldn't work.

Martin Peck
+2  A: 

It is not possible to simply cast one object other type even if thay have one parent, because thay maybe have different interfaces.

You need to implement explicit or implitic operator of ChildA (or ChildB).

class ClassA
{
    public string Property1 { get; set; }
}

class ClassB
{
    public string Property2 { get; set; }

    public static implicit operator ClassB(ClassA classA)
    {
        return new ClassB() { Property2 = classA.Property1 };
    }
}

or

class ClassA
{    {
    public string Property1 { get; set; }

    public static explicit operator ClassB(ClassA classA)
    {
        return new ClassB() { Property2 = classA.Property1 };
    }
}

class ClassB
{
    public string Property2 { get; set; }
}

And after implementing conversings operators following code will work fine:

var a = new ClassA() {Property1 = "test"};
ClassB b = (ClassB)a;
Console.WriteLine(b.Property2); // output is "test"

In first case you can omit explicitely type conversion and write just like this:

var a = new ClassA() {Property1 = "test"};
ClassB b = a;

And finally if you want to synchronize only properties of parent class you can write converter directly in parent:

class Parent
{
    public string ParentProperty { get; set; }
    public static T1 Convert<T1>(Parent obj) where T1 : Parent, new()   
    {
    var result = new T1();
    result.ParentProperty = obj.ParentProperty;
    return result;
    }
}

Using (ClassA and ClassB childs of Parent):

var a = new ClassA();
a.ParentProperty = "test";
ClassB b = Parent.Convert<ClassB>(a);
Console.WriteLine(b.ParentProperty); // output is "test"
bniwredyc
Thanks for your more in-depth explanation of Jons more general answer - even though your posts seems to be parallel =)
Chau
@Chau you're welcome (%
bniwredyc
A: 

ChildA and ChildB are different types which share the same parent. Thus you can treat instances of both ChildA and ChildB as their base, Parent, but as they are different types you can't cast one to the other.

Brian Rasmussen
A: 

As others say ChildA is not ChildB. If ChildA and B have the same properties/functions then you should do:

public class Parent{}
public class Child : Parent{}

Child objA = new Child();
Child objB = objA;

But I gues this is only an example, you got a real live example why you want to achieve something like this?

PoweRoy