Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Casting between classes that share the same interface

I have two interfaces IHeaderRow, and IDetailRow

I then have an object that implements both RawRow:IHeaderRow, IDetailRow

I then need to cast it to HeaderRow which implements IHeaderRow.

But when I try, it ends up being null or giving an exception.

I can cast ObjectRawRow to either interface IHeaderRow, or IDetailRow

var ObjectIHeaderRow = ObjectRawRow as IHeaderRow;
var ObjectIDetailRow = ObjectRawRow as IDetailRow;

But I can not cast ObjectRawRow to HeaderRow , or ObjectIHeaderRow to HeaderRow.

It throws the error Cannot convert source type 'IA' to target type 'A'

I need to cast it into the actual class HeaderRow.

Thoughts?

EDIT:

Even though setting up an explicit cast took care of the issue I thought I'd provide an answer to the people wondering, WHY I was doing what I was.

In short, I'm sequentially processing a file. Line by line. I read the row into RawRow, and until I look at a few values, I don't actually know what type of row it is going to be. I then wanted to cast it to the proper type.

like image 671
CaffGeek Avatar asked Apr 15 '10 19:04

CaffGeek


People also ask

What happens when two classes implement the same interface?

A class can implement multiple interfaces and many classes can implement the same interface. A class can implement multiple interfaces and many classes can implement the same interface. Final method can't be overridden. Thus, an abstract function can't be final.

What is interface casting?

A type cast—or simply a cast— is an explicit indication to convert a value from one data type to another compatible data type. A Java interface contains publicly defined constants and the headers of public methods that a class can define.

Can a class be cast to an interface?

Yes, you can. If you implement an interface and provide body to its methods from a class. You can hold object of the that class using the reference variable of the interface i.e. cast an object reference to an interface reference.

What is the relationship between class and interface?

RELATIONSHIP BETWEEN CLASS AND INTERFACEA class can extend another class, an interface can extend another interface, but a class implements an interface.


3 Answers

You can only implicitly cast objects to types they inherit from or implement - since RawRow doesn't derive from HeaderRow, it's not possible.

Depending on your requirements, you could overcome this by writing an explicit conversion operator, creating a HeaderRow constructor that accepts a RawRow as its prototype, or by modifying your code to operate on an IHeaderRow.

like image 122
Jeff Sternal Avatar answered Sep 21 '22 17:09

Jeff Sternal


Why do you need to cast it to a HeaderRow in the first place? If IHeaderRow produced the api that a HeaderRow implements, than you should just be able to act on IHeaderRow "objects" using the defined methods.

The point of an interface is so that you can treat a grouping of different objects as a similar type. Not so that you can cast different objects between classes that are not linked by inheritance.

like image 32
unholysampler Avatar answered Sep 21 '22 17:09

unholysampler


First, why do you need to do such a weird cast? There's probably another design for what you're trying to do.

Second, the reason you can't do the cast is because a RawRow isn't an HeaderRow. The only guarantee it makes is that it implements IHeaderRow. The problem is that it has a bunch of other stuff too, stuff that HeaderRow doesn't have. And vice versa - HeaderRow probably has a bunch of stuff that ObjectRawRow doesn't have.

Imagine your classes look like this:

interface IHeaderRow
{
    string GetText();
}

class HeaderRow : IHeaderRow
{
    public string GetText()
    { 
        return "My Label";
    }

    public int GetFoo()
    {
        return 42;
    }
}

class ObjectRawRow : IHeaderRow
{
    public string GetText()
    {
        return "My Raw Label";
    }
}

Now if you do this, you're ok:

ObjectRawRow row = new ObjectRawRow();
IHeaderRow header = row as IHeaderRow;
string label = header.GetText();    // fine, since GetText is guaranteed to exist

But try this on for size:

ObjectRawRow row = new ObjectRawRow();
HeaderRow header = row as HeaderRow;
int magic = header.GetFoo();       // BOOM! Method doesn't exist,
// because the object isn't really a HeaderRow under the covers.
// It's still really an ObjectRawRow. What do you do now? Crash hard is what.

And that's why you can't cast outside of the inheritance tree.

like image 30
Tesserex Avatar answered Sep 20 '22 17:09

Tesserex