Кастинг между двумя типами, производными от (того же) интерфейса

У меня есть интерфейс и два типа, которые вытекают из него.

Однако я не могу сделать следующее:

B objectB = (B) objectA

Где B происходит из интерфейса1 (я составляю название классов, но точка все еще стоит), а также для объекта A (который относится к типу A). Появляется следующее сообщение об ошибке:

Невозможно выразить выражение типа A-B.

Оба типа выводятся из интерфейса, что мне не хватает?

Ответ 1

  • Типы не выводятся из интерфейса. Они реализуют интерфейс.
  • Тот факт, что и Слон, и Паук - животные, не означает что вы можете конвертировать один в другой.

Ответ 2

Вы не можете отличать или конвертировать из A в B, если все они являются общим интерфейсом, если вы фактически не определяете свой собственный оператор преобразования, если вы контролируете источник для одного из типов или используете другой предоставленный пользовательский интерфейс, определенному преобразованием, предоставленным кем-то, кто контролирует источник. (Тем не менее, такие пользовательские преобразования не будут сохранять исходный объект. Один объект переходит в преобразование, появляется другой объект.)

Вы можете конвертировать из A в Interface1 и B в Interface1. Но два типа, просто разделяющих общий родительский элемент, не делают эти два типа конвертируемыми друг к другу.

A a = new A(); 
B b = new B();
Interface1 obj1 = a; // legal
Interface1 obj2 = b; // legal
B obj3 = (B)a; // not legal, a is simply not a B

tobias86 хорошо вписывается в комментарий ниже, у вас есть кошка и собака. Оба получаются из Animal. Но кошка просто не собака.


В качестве расширения вы можете столкнуться с тем, как и почему вы будете использовать интерфейс. Вы не используете интерфейс для замены A для B или B для A. Вы используете его для замены A или B для интерфейса1. Это интерфейс, который вы ожидаете, и A или B, которые вы можете поставить. Дано:

public void DoSomething(Interface1 obj) { } // expects 
DoSomething(new A()); // you can supply A

Или

public Interface1 GetSomething() // callers expect to get 
{
    return new B(); // you can supply a B
}

Это интерфейс, к которому вы программируете, A и B - это просто реализации. Возможно, вы думаете, что можете передать B на то, что ожидает A. Ожидание, возможно, должно измениться.

Ответ 3

Тот факт, что оба типа реализуют один и тот же интерфейс (или имеют тот же базовый тип, если на то пошло), не делают их взаимозаменяемыми; a A всегда A, a B всегда a B. В цепочке наследования объект может быть отброшен как сам или какой-либо родительский тип. У вас есть:

A : ISomeInterface
B : ISomeInterface

который позволяет использовать A как A или ISomeInterface, а B как B или ISomeInterface

или (в зависимости от вашего значения "производное от" )

SomeBaseType
 > A
 > B

который позволяет использовать A как A или SomeBaseType, а B как B или SomeBaseType

(плюс object, в каждом случае)

Ответ 4

Объект присваивается предку или интерфейсу, который он реализует, но не братьям и сестрам (т.е. Другому типу, происходящему от общего предка); однако вы можете объявить свои собственные явные преобразования:

class FooObject : IObject
{
    public string Name { get; set; }
    public int Value { get; set; }

    public static explicit operator FooObject(BarObject bar)
    {
        return new FooObject { Name = bar.Name, Value = bar.Value };
    }
}

class BarObject : IObject
{
    public string Name { get; set; }
    public int Value { get; set; }

    public static explicit operator BarObject(FooObject bar)
    {
        return new BarObject { Name = bar.Name, Value = bar.Value };
    }
}

Теперь вы можете написать

var foo = new FooObject();
var bar = (BarObject)foo;

или же

var bar = new BarObject();
var foo = (FooObject)bar;

без получения ошибок.

Вы также можете создавать implicit преобразования, если это кажется естественным. Например, int неявно конвертируется в double: int я = 5; double x = i; int я = 5; double x = i; ,

(Это также ответ на закрытый вопрос. Как преобразовать класс FooObject в класс BarObject, который реализует интерфейс IObject?).

Ответ 5

Когда кастинг от A до B B должен быть супер-типом для A или тип времени выполнения объекта должен быть B

если у вас есть

class A : B{}

вы можете наложить объект времени компиляции типа A на B. Вы также можете указать тип B в A, если тип времени выполнения объекта A

в вашем случае два типа не разделяют отношения супер-подтипов. Они имеют общий общий тип супер, но этого недостаточно.

В качестве примера, почему это не может работать (в общем), как бы у вас был компилятор с Point[] на Dictionary<string,HashSet<byte>>? (оба реализуют IEnumerable)

Ответ 6

То, что вы хотите сделать, не имеет смысла. objectA не является B.

Ответ 7

Вы можете использовать их только для типа интерфейса. A не B, но они оба I. Это означает, что вы можете взять A и наложить на я или B и наложить на I, но не на B, и наложить на A

Ответ 8

Вам нужно указать в качестве интерфейса.

interface IBase { }
class A : IBase { }
class B : IBase { }

При этом единственное, что имеют два типа, это члены интерфейса. B может иметь элементы, которые A не поддерживает.

A a = new A();
B b = new B();

IBase aBase = a;
IBase bBase = b;

Затем вы можете вызвать что-либо на интерфейсе IBase.

Ответ 9

Представьте следующую настройку:

public interface Human
{
    bool Male { get; }
}

public class Man : Human
{
    public bool HasABeard { get { return true; } }

    public bool IsMale { get { return true; } }
}

public class Woman : Human
{
    public bool IsMale { get { return false; } }

    public List<Pair<Shoe>> Shoes { get; set; }
}

Что вы ожидаете от компилятора из следующего кода? Каким будет выход?

Man a;
Woman b = new Woman();
a = (Man)b;

Console.WriteLine(a.HasABeard ? "Beard ON" : "Beard OFF");