Приведение между классами с одинаковым интерфейсом - PullRequest
7 голосов
/ 15 апреля 2010

У меня есть два интерфейса IHeaderRow и IDetailRow

Затем у меня есть объект, который реализует оба RawRow: IHeaderRow, IDetailRow

Затем мне нужно привести его к HeaderRow , который реализует IHeaderRow .

Но когда я пытаюсь это сделать, он становится нулевым или дает исключение.

Я могу разыграть ObjectRawRow на любой интерфейс IHeaderRow или IDetailRow

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

Но я не могу разыграть ObjectRawRow в HeaderRow или ObjectIHeaderRow в HeaderRow .

Выдает ошибку Невозможно преобразовать тип источника 'IA'to target type' A '

Мне нужно привести его в реальный класс HeaderRow .

Мысли?

РЕДАКТИРОВАТЬ:

Несмотря на то, что настройка явного актерского состава позаботилась о проблеме, я подумал, что дам ответ людям, которые задаются вопросом, ПОЧЕМУ я делал то, что я был.

IКороче говоря, я последовательно обрабатываю файл.Построчно.Я прочитал строку в RawRow, и пока я не посмотрю на несколько значений, я на самом деле не знаю, какой это будет строка.Затем я хотел привести его к нужному типу.

Ответы [ 7 ]

6 голосов
/ 15 апреля 2010

Вы можете неявно приводить объекты только к тем типам, от которых они наследуют или реализуют - поскольку RawRow не является производным от HeaderRow, это невозможно.

В зависимости от ваших требований вы можете преодолеть это, написав оператор явного преобразования , создав конструктор HeaderRow, который принимает RawRow в качестве прототипа, или изменив код для работы с IHeaderRow.

4 голосов
/ 15 апреля 2010

Зачем вам нужно сначала привести его к HeaderRow? Если IHeaderRow создал API, который реализует HeaderRow, то вы должны просто иметь возможность воздействовать на «объекты» IHeaderRow, используя определенные методы.

Смысл интерфейса в том, что вы можете рассматривать группировку различных объектов как похожий тип. Не так, что вы можете приводить разные объекты между классами, которые не связаны наследованием.

2 голосов
/ 15 апреля 2010

Во-первых, зачем вам делать такие странные актеры?Вероятно, есть другой дизайн того, что вы пытаетесь сделать.

Во-вторых, причина, по которой вы не можете выполнять приведение, состоит в том, что 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.

И вот почему вы не можете разыгрывать вне дерева наследования.

1 голос
/ 15 апреля 2010

Вы не сможете выполнить это приведение, если между типами нет отношений наследования. Если это невозможно, лучшее, что вы можете сделать, - это создать явный оператор преобразования, который позволит вам преобразовывать один тип в другой.

Если вы создаете явное преобразование, вы должны понимать, что это будет медленнее, чем приведение, поскольку вы будете вызывать метод, который будет работать, а не приведение, которое только изменяет ссылочный тип и не изменяет никакой памяти в кучу.

Рассмотрим пример, который не компилируется:

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

class Foo { }
class Bar { }

Поскольку между типами нет отношений наследования и нет явного преобразования из Foo в Bar, компиляция невозможна.

Но добавление явного преобразования позволяет скомпилировать:

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 { }
1 голос
/ 15 апреля 2010

Вы не можете привести 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;
0 голосов
/ 15 апреля 2010

Вы можете использовать явное ключевое слово для создания методов, которые будут вызываться при попытке привести от IA к A. Причина, по которой это не работает без написания собственного метода, заключается в том, что компилятор не знает, что делать со значениями, которые не предоставляются.

0 голосов
/ 15 апреля 2010

Вы можете привести экземпляр только к определенному классу, если объект на самом деле является экземпляром этого класса (или является производным от этого класса).

Невозможно привести экземпляр класса A к совершенно не связанному классу B (что вы и пытаетесь сделать), даже если они реализуют одинаковые интерфейсы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...