views:

58

answers:

3

Hello.

I have a product class in C# that inherits from another product class

using ExternalAssemb.ProductA;

public class MyProduct : ProductA
{
    //....
}

I'm trying to do an explicit cast from ProductA that is in a DLL I reference but it's telling me it's unable to cast

MyProduct myProduct = (MyProduct)productAobject;

Result:: System.InvalidCastException: Unable to cast object of type 'ExternalAssemb.ProductA' to type 'MyAssembly.MyProduct'.

What am I doing wrong?

+4  A: 

You can cast a ProductA reference to a MyProduct reference, but only if it actually points to MyProductA or a child thereof.

What you're doing is trying to treat the parent like a child, that's doesn't work. Rather, you can treat the child like the parent, because it is like the parent.

Think of a generic example where a base class is called Shape and has children such as Square and Circle. Given a Shape reference, you can assign any child to it. But if the reference refers to a Circle, you can't cast it to a Square. This makes sense, because all circles are shapes, but no circles are squares.

Hope the examples help.

Steven Sudit
or if explicit casting operator is implemented for `ProductA`
zerkms
@zerkms: That's true, but it's also a separate thing from natural inheritance. Nothing stops me from having `Aardvark` define an explicit cast to `Building`, but this has nothing to do with aardvarks actually being buildings. Instead, the `Aarvark` instance has to return a `Building` instance, likely by creating one. In short, it looks like casting, but it's not *really* casting.
Steven Sudit
if I cast MyProduct to ProductA how do I get to MyProduct properties. Do I have to do this everytime? ((MyProduct)ProductA).MyProductProperty.
@user204588: If you take a `MyProduct` instance and hold it in a `ProductA` reference, then you will only be able to treat it as a `ProductA`. If you need any of the special properties of `MyProduct`, then you will have to downcast. However, if you use virtual, then you can call through the parent but get the implementation by the child.
Steven Sudit
@Steven: ah, yes, their correct name is **conversion** operators...
zerkms
@zerkms: Exactly. Conversion is nice, but potentially lossy. When you convert a `long` to an `int`, you may lose part of the original value. In fact, that's why that conversion is explicit, whereas `int` to `long` is implicit.
Steven Sudit
A: 

Every MyProduct is also a ProductA, but the reverse is not true. productAobject is an explicit instance of ProductA; it's not a MyProduct at all.

Similarly, given another class:

public class FooProduct : ProductA
{
    //....
}

...you could not do this:

ProductA myFooProduct = new FooProduct();
MyProduct myProduct = (MyProduct)myFooProduct;

...since FooProduct does not inherit from MyProduct.

The rule is: you can only cast an instance of a class to itself or one of its ancestor classes. You cannot cast it to any descendant or any other sibling/cousin class in the inheritance tree.

Remember that we're talking about the actual type of the instance here. It is irrelevant what the type of the variable that holds it is.

Craig Walker
This isn't wrong, but it's a bit misleading. A reference of type `ProductA` *might* refer to a `FooProduct`, but then again, it might not. That's why the cast is legal, but might fail during runtime.
Steven Sudit
In specific, you're not distinguishing clearly between references and instances.
Steven Sudit
Hi @Steven. I'm not sure where I'm not being clear; I do say that the instance and not the reference (variable) is what ultimately matters. If you can explain then I'll edit my post appropriately.
Craig Walker
+1  A: 

Quite simply, when you downcast, which may or may not succeed, you need to use is/as operators to check if the instance of ProductA is really MyProduct:

MyProduct myProduct = productAobject as MyProduct;
if (myProduct != null) {
  //valid MyProduct instance
} else {
  //productAobject is not really an instance of MyProduct 
}
Igor Zevaka
Sure, unless failure would be an exception, in which case the regular casting operator is best.
Steven Sudit