Как исправить ошибки Cast при приведении общих параметров - PullRequest
0 голосов
/ 29 декабря 2018

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

Пример

ICage<TAnimal> isинтерфейсу для Cage животного типа IAnimal

public interface ICage<TAnimal>
    where TAnimal : IAnimal<IOwner>

public class Cage<TAnimal> : ICage<TAnimal>
    where TAnimal : IAnimal<IOwner>

public interface IAnimal<out TOwner>
    where TOwner : IOwner

IAnimal нужен владелец типа IOwner

public abstract class Mammal<TOwner> : IAnimal<TOwner>
    where TOwner : IOwner

Млекопитающее - это типЖивотное с владельцем типа IOwner.

public class Human : IOwner

A Human - это тип IOwner

public class Dog<TOwner> : Mammal<TOwner>
    where TOwner : IOwner

Собака - это тип млекопитающего.

Теперь собираем все вместе:

 var cage = new Cage<Mammal<IOwner>>();
 var me = new Human()
 {
     Name = "Hakim"
 };
 var dog = new Dog<Human>();
 dog.Owner = me;
 cage.Add((Mammal<IOwner>)dog);

В последней строке я получаю ошибку времени компиляции CS0030, говорящую мне, что я не могу конвертировать Dog в Mammel.

1 Ответ

0 голосов
/ 29 декабря 2018

Это та же самая причина, по которой вы не можете разыграть List<string> до List<object>.

Допустим, в Mammal есть свойство с именем Ownerнапример:

public TOwner Owner { get; set; }

Для экземпляра Mammal<IOwner> это становится:

public IOwner Owner { get; set; }

dog - это Dog<Human>, что также является Mammal<Human>. Если вы можете привести dog к Mammal<IOwner>, это будет означать, что dog.Owner может внезапно хранить любой тип, который реализует IOwner.то есть это было бы возможно:

class EvilOwner : IOwner { ... }

Mammal<IOwner> mammal = (Mammal<IOwner>)dog;
mammal.Owner = new EvilOwner();

Но это невозможно, потому что dog во время выполнения - это Dog<Human>, который имеет Owner Human.EvilOwner не может быть сохранено в Human!

Я предлагаю вам удалить общий параметр TOwner.Если, по вашему мнению, Dog<Human> также является разновидностью Mammal<IOwner>, то, вероятно, имеет смысл проектировать классы следующим образом:

public interface IAnimal {
    IOwner Owner { get; }
}

public abstract class Mammal : IAnimal { ... }

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