2010-04-15 5 views
7

У меня есть два интерфейса IHeaderRow и IDetailRowCasting между классами, которые разделяют один и тот же интерфейс

Я тогда объект, который реализует как RawRow: IHeaderRow, IDetailRow

тогда мне нужно лить его в HeaderRow который реализует IHeaderRow.

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

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

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

Но я не могу бросить ObjectRawRow к HeaderRow или ObjectIHeaderRow к HeaderRow.

Он бросает ошибку Не удается преобразовать тип источника «IA» в целевой тип «А»

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

Мысли?

EDIT:

Несмотря на создание явное приведение позаботилась о проблеме я думал, что дать ответ людям, интересно, почему я делаю то, что я был.

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

+0

Какой тип 'ObjectRawRow' объявлен? – SLaks

+0

@SLaks, ObjectRawRow - это RawRow (который реализует IHeaderRow и IDetailRow) – CaffGeek

+0

. Лучшим способом сделать это может быть просто заставить RawRow создать экземпляр соответствующего экземпляра (действующего как * Factory *), используя конструктор копирования, если хотите. –

ответ

6

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

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

+0

Оператор преобразования работал отлично. Это беспокоило меня так много раз. Все работает отлично, как интерфейсы, пока я не попытаюсь сериализовать объект. Затем я заканчиваю тем, что меняю определение с интерфейсов на классы ... и затем фактически не может заполнить его из-за этого ограничения каста – CaffGeek

+0

Маленький языковой каламбур, OP пытается сделать * явным * литье, и ему необходимо реализовать * пользовательский оператор неявного преобразования *. –

+0

@Steven - интересно, почему вы так говорите? Я изначально не указал явный оператор, но потом по какой-то причине поменял его - я думаю, это звучит так, будто преобразование может быть потерянным или потенциально может вызвать исключение. Полагаю, из вопроса не ясно, поэтому я могу просто изменить его на неопределенный. –

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; 
1

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

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

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

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

Gah, извините, Андрей, я отредактировал твой, а не мой, а потом откинул назад. D: –

+0

@Jeff - Не беспокойтесь! Я делал это много раз перед собой :) –

0

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

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

0

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

+0

Операторы роли вызываются во время компиляции. Они могут не помочь здесь. – SLaks

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. 

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

+0

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

+0

Это не то, что вы технически не могли, я думаю, но компилятор даже не позволит вам приблизиться, чтобы попробовать. Это даже не позволит вам нарисовать ObjectRawRow в HeaderRow, потому что тогда вы настраиваете себя на возможность сбоя CLR. «Контракт», который безопасно вызывать любые и все методы HeaderRow, должен поддерживаться в любое время. – Tesserex

+0

«Компилятор не будет»: HeaderRow hr = (HeaderRow) (объект) someObjectRawRow; –

4

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

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

Смежные вопросы