可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
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.
回答1:
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
.
回答2:
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.
回答3:
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.
回答4:
You cannot cast ObjectRawRow to HeaderRow unless one inherits from the other.
Interfaces have nothing to do with it.
Consider:
class Shape
interface IHasCorners
class Rectangle : IHasCorners, Shape
class Triangle : IHasCorners, Shape
Rectangle myRectangle = new Rectangle();
Triangle myTriangle = new Triangle();
//upcasts
Shape s = (Shape)myRectangle;
IHasCorners hc = (IHasCorners)myRectangle;
//downcasts
Rectangle r2 = (Rectangle)s;
r2 = (Rectangle)hc;
//upcasts
s = (Shape)myTriangle;
hc = (IHasCorners) myTriangle;
//these downcasts won't work
//the variables now reference a Triangle instance
Rectangle r3 = (Rectangle)s;
r3 = (Rectangle)hc;
回答5:
You will not be able to make this cast unless there is an inheritance relationship between the types. If that is not possible then the best you can do is create an explicit conversion operator that allows you to cast one type as another type.
If you do create an explicit conversion you should understand that this will be slower than casting as you will be invoking an method that will do work as opposed to casting which only changes the reference type and doesn't change any of the memory on the heap.
Consider this example that doesn't compile:
class Example
{
static void Main()
{
Foo foo = new Foo();
Bar bar = (Bar)foo;
}
}
class Foo { }
class Bar { }
Since there is no inheritance relations between the types nor is there an explicit conversion from Foo
to Bar
this cannot compile.
But adding an explicit conversion allows it to compile:
class Example
{
static void Main()
{
Foo foo = new Foo();
Bar bar = (Bar)foo;
}
}
class Foo
{
public static explicit operator Bar(Foo foo)
{
return new Bar();
}
}
class Bar { }
回答6:
You can only cast an instance to a particular class if the object is actually an instance of that class (or is derived from that class).
It is not possible to cast an instance of class A to completely unrelated class B (which is what you're trying to do), even if they implement the same interfaces.
回答7:
You can use the explicit keyword to create methods that will be called when you try to cast from IA
to A
. The reason it doesn't work without you writing your own method is because the compiler doesn't know what to do with the values that aren't being provided.