У меня есть два интерфейса 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' для предназначения для типа
Я должен бросить его в фактический класс HeaderRow.
Мысли?
Править:
Даже при том, что установка явного броска заботилась о проблеме, я думал, что предоставлю ответ людям, задающимся вопросом, ПОЧЕМУ я делал, кто я был.
Короче говоря, я последовательно обрабатываю файл. Линию за линией. Я считал строку в RawRow, и пока я не смотрю на несколько значений, я на самом деле не знаю, какой строкой это будет. Я затем хотел бросить его к надлежащему типу.
Вы можете только неявно приводить объекты к типам, которые они наследуют или реализуют - поскольку RawRow
не является производным от HeaderRow
, это невозможно.
В зависимости от ваших требований, вы можете преодолеть это, написав оператор явного преобразования , создав конструктор HeaderRow
, который принимает RawRow
в качестве своего прототипа, или путем изменения кода для работы с IHeaderRow
.
Вы не можете преобразовать 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;
Почему вам вообще нужно преобразовать его в HeaderRow? Если IHeaderRow создал api, который реализует HeaderRow, тогда вы должны просто иметь возможность воздействовать на «объекты» IHeaderRow, используя определенные методы.
Смысл интерфейса в том, что вы можете рассматривать группу различных объектов как один и тот же тип. Не то чтобы вы могли преобразовывать разные объекты между классами, не связанными наследованием.
Во-первых, зачем вам такое странное приведение? Вероятно, есть другой дизайн для того, что вы пытаетесь сделать.
Во-вторых, вы не можете выполнить приведение по той причине, что 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.
И вот почему вы не можете преобразовать за пределы дерева наследования .
Вы можете привести экземпляр к определенному классу только в том случае, если объект на самом деле является экземпляром этого класса (или является производным от этого класса).
Невозможно привести экземпляр класса A к полностью несвязанному классу B (что вы и пытаетесь сделать), даже если они реализуют одни и те же интерфейсы.
Вы можете использовать явное ключевое слово для создания методов, которые будут вызываться при попытке приведения из IA
к A
. Причина, по которой он не работает без написания собственного метода, заключается в том, что компилятор не знает, что делать со значениями, которые не предоставляются.
Вы не сможете выполнить это приведение, если между типами нет отношения наследования. Если это невозможно, лучшее, что вы можете сделать, - это создать оператор явного преобразования, который позволяет преобразовать один тип в другой.
Если вы действительно создаете явное преобразование, вы должны понимать, что это будет медленнее, чем преобразование, поскольку вы будете вызывать метод, который будет работать, в отличие от преобразования, которое изменяет только ссылочный тип и не меняет никакой памяти. в куче.
Рассмотрим этот пример, который не компилируется:
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 { }