在共享相同接口的类之间进行转换

时间:2010-04-15 19:21:33

标签: c# interface casting

我有两个接口 IHeaderRow IDetailRow

然后我有一个实现 RawRow:IHeaderRow,IDetailRow

的对象

然后,我需要将其强制转换为实现 IHeaderRow HeaderRow

但是当我尝试时,它最终会变为空或给出异常。

我可以将 ObjectRawRow 投射到接口 IHeaderRow IDetailRow

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

但我无法将 ObjectRawRow 投射到 HeaderRow ,或 ObjectIHeaderRow 投放到 HeaderRow

它抛出错误无法将源类型'IA'转换为目标类型'A'

我需要将它投射到实际的类 HeaderRow

思想?

编辑:

即使设立一个明确的演员照顾这个问题,我想我会为那些想知道的人提供一个答案,为什么我这样做。

简而言之,我正在按顺序处理文件。逐行。我将行读入RawRow,直到我看到一些值,我实际上并不知道它将是什么类型的行。然后我想将它转换为正确的类型。

7 个答案:

答案 0 :(得分:6)

您只能隐式地将对象转换为它们继承或实现的类型 - 因为RawRow不是从HeaderRow派生的,所以不可能。

根据您的要求,您可以通过编写explicit conversion operator,创建一个HeaderRow构造函数来接受RawRow作为其原型,或者通过修改代码来操作IHeaderRow

答案 1 :(得分:4)

为什么首先需要将它投射到HeaderRow?如果IHeaderRow生成了HeaderRow实现的api,那么你应该能够使用定义的方法对IHeaderRow“对象”进行操作。

接口的要点是,您可以将不同对象的分组视为相似类型。不是这样你可以在没有通过继承链接的类之间转换不同的对象。

答案 2 :(得分:2)

首先,你为什么要做这样一个奇怪的演员?对于你想要做的事情,可能还有另一种设计。

其次,你无法进行强制转换的原因是因为RawRow 不是 HeaderRow。它唯一的保证是它实现了IHeaderRow。问题是它还有很多其他的东西,HeaderRow没有的东西。反之亦然 - HeaderRow可能有一堆ObjectRawRow没有的东西。

想象一下你的课程如下:

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";
    }
}

现在,如果你这样做,你就可以了:

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

但请尝试以下尺寸:

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.

这就是为什么你不能在继承树之外进行投射。

答案 3 :(得分:1)

除非从另一个继承,否则不能将ObjectRawRow强制转换为HeaderRow。

接口与它无关。


考虑:

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;

答案 4 :(得分:1)

除非类型之间存在继承关系,否则您将无法进行此转换。如果那是不可能的,那么您可以做的最好的事情是创建一个显式转换运算符,允许您将一种类型转换为另一种类型。

如果你确实创建了一个显式转换,你应该明白这比转换要慢,因为你将调用一个方法,它会起作用,而不是仅仅改变引用类型并且不改变任何内存的转换在堆上。

考虑这个不编译的例子:

class Example
{
    static void Main()
    {
        Foo foo = new Foo();
        Bar bar = (Bar)foo;
    }
}

class Foo { }
class Bar { }

由于类型之间没有继承关系,也没有从FooBar的显式转换,因此无法编译。

但添加显式转换允许它编译:

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 { }

答案 5 :(得分:0)

如果对象实际上是该类的实例(或从该类派生),则只能将实例强制转换为特定类。

不可能将类A的实例强制转换为完全不相关的类B(这是您正在尝试做的事情),即使它们实现了相同的接口。

答案 6 :(得分:0)

您可以使用explicit keyword创建在尝试从IA投射到A时将调用的方法。没有编写自己的方法它不起作用的原因是因为编译器不知道如何处理未提供的值。