Полиморфизм C# простой вопрос

Я получил класс X и класс Y, последний, который происходит от X:

class x {}
class y : x {}

Тогда где-нибудь я использую список X:

List<X> lstX;
...

Тогда я хотел бы использовать новый список Y от данных в моем другом списке... что-то вдоль тех строк:

List<Y> lstY = lstX;

Я полагал бы, что объекты в списке X преобразовать автоматически в Y, но это не имеет место.

Кроме того, как я мог инициализировать новый экземпляр Y от определенного X? Я хотел бы сделать:

var newX = new X();
var newY = new Y(X);

но это, кажется, не работает как этот.

Спасибо за помощь! и жаль о форматировании, стараясь изо всех сил

9
задан CoderDennis 9 February 2010 в 19:28
поделиться

6 ответов

Здесь есть пара вопросов.

Первый: "Я могу присвоить объект типа Tiger переменной типа Animal. Почему я не могу присвоить объект типа List of Tiger переменной типа List of Animal?"

Потому что тогда произойдет следующее:

List<Tiger> tigers = new List<Tiger>();
List<Animal> animals = tigers; // this is illegal because if we allow it...
animals.Add(new Giraffe()); // ... then you just put a giraffe into a list of tigers.

В C# 4 это будет законно:

IEnumerable<Tiger> tigers = new List<Tiger>();
IEnumerable<Animal> animals = tigers;

Это законно, потому что IEnumerable не имеет метода "Add" и поэтому это гарантированно безопасно.

Подробности об этой новой возможности C# 4 смотрите в моей серии статей о ковариации.

http://blogs.msdn.com/ericlippert/archive/tags/Covariance+and+Contravariance/default.aspx

Второй вопрос: "Как я могу инициализировать новый экземпляр Tiger из определенного Animal?"

Вы не можете. Животное, о котором идет речь, может быть божьей коровкой. Как вы собираетесь инициализировать нового Тигра из экземпляра Божьей коровки? В этом нет никакого смысла, поэтому мы не разрешаем вам этого делать. Если вы хотите написать свой собственный специальный метод, который умеет превращать произвольных животных в тигров, вы можете это сделать. Но мы не знаем, как сделать это за вас.

27
ответ дан 4 December 2019 в 06:56
поделиться

Это никогда не сработает; в конце концов List lstY = lstX; просто копирует ссылку (если вы не добавляете свой собственный оператор неявного статического преобразования в свой тип списка) - так что это по-прежнему список X и может содержать объекты , отличные от , кроме Y экземпляров.

Даже в 4.0 вариация co / contra не распространяется на списки a: (оба в и из ) или b: конкретные типы (например, List < T> ).

Интересно, что он будет (и всегда работал) для массивов ссылочных типов, но только в направлении X [] arrX = arrY; . Он ничего не конвертирует; если вы попытаетесь ввести неправильные данные, это вызовет исключение.

3
ответ дан 4 December 2019 в 06:56
поделиться

Нет, поскольку вы не можете быть уверены, что все элементы в listX, которые относятся к типу 'X', также относятся к типу Y.
Отношение наследования обратное: элемент типа Y можно преобразовать в X, потому что Y is-a X.

В C # также нет доступных «конструкторов копирования», как в C ++, поэтому я боюсь, что вам придется реализуйте эту логику, чтобы иметь возможность самостоятельно инициализировать новый экземпляр Y из определенного X. Также имейте в виду, что классы являются ссылочными типами ...

1
ответ дан 4 December 2019 в 06:56
поделиться

Ваш сценарий как бы отличается от обычных полиморфных вариантов использования. Y - это X, но X - это не Y.

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

0
ответ дан 4 December 2019 в 06:56
поделиться

Он не может автоматически "расширять" тип объектов с x до y, потому что X - это не Y, но Y равно X.

Вы можете попробовать преобразование из X в Y, но это не удастся с InvalidCastException , если ваш объект изначально не был маскирующим по Y как X все время. Вам необходимо инициализировать и заполнить новый List вручную:

IList<Y> yList = new List<Y>();
foreach (var x in xList)
{
    var y = new Y(x); // Copies/clones inherited properties from x to a new Y
    // TODO: Set other properties of y not present on x
    yList.Add(y);
}
1
ответ дан 4 December 2019 в 06:56
поделиться

Проблема, с которой вы столкнетесь с вашим первым примером, состоит в том, что Y происходит от X, поэтому это «X», но «X не является Y ", также C # в настоящее время не поддерживает приведение типов в этом методе. Вы можете попробовать использовать методы расширения для Cast, такие как lstX.ConvertAll, в качестве помощника для этого.

По второму вопросу вы хотите изучить конструктор копирования, например:

public Y(X baseObject) {
   //copy all the data you need here...
}
0
ответ дан 4 December 2019 в 06:56
поделиться
Другие вопросы по тегам:

Похожие вопросы: