Нет, селектор «предыдущего сиблинга» отсутствует.
В соответствующей заметке ~
используется для общего брака-последователя (это означает, что элемент появляется после этого, но не обязательно сразу после) и является селектором CSS3. +
для следующего родного брата и является CSS2.1.
См. Комбинированный смежный блок-класс из Селектора уровня 3 и 5.7 Смежные селекторные ролики из Каскадные таблицы стилей Уровень 2 Редакция 1 (CSS 2.1) Спецификация .
Причина, по которой вы не можете сделать это, состоит в том, что список доступен для записи. Предположим, что это было законно, и посмотрите, что пойдет не так:
List<Cat> cats = new List<Cat>();
List<Animal> animals = cats; // Trouble brewing...
animals.Add(new Dog()); // hey, we just added a dog to a list of cats...
cats[0].Speak(); // Woof!
Хорошо, собака, мои кошки, это плохо.
Функция, которую вы хотите, называется «общей ковариацией», и она поддерживается в C # 4 для интерфейсов, которые, как известно, являются безопасными. IEnumerable<T>
не имеет никакого способа записи в последовательность, поэтому он безопасен.
class Animal
{
public virtual void Play(IEnumerable<Animal> animals) { }
}
class Cat : Animal
{
public override void Play(IEnumerable<Animal> animals) { }
}
class Program
{
static void Main()
{
Cat cat = new Cat();
cat.Play(new List<Cat>());
}
}
Это будет работать на C # 4, потому что List<Cat>
конвертируется в IEnumerable<Cat>
, который можно конвертировать в IEnumerable<Animal>
. Нельзя использовать Play IEnumerable<Animal>
, чтобы добавить собаку к тому, что на самом деле является списком кошек.
Вы могли бы сделать несколько вещей. Например, элементы списка относятся к Animal
. Использование вашего кода:
cat.Play(new List<Cat>().Cast<Animal>().ToList());
Другим является создание Animal
общего, поэтому cat.Play(new List<Cat>());
будет работать.
class Animal<T>
{
public virtual void Play(List<T> animals) { }
}
class Cat : Animal<Cat>
{
public override void Play(List<Cat> cats)
{
}
}
class Program
{
static void Main(string[] args)
{
Cat cat = new Cat();
cat.Play(new List<Cat>());
}
}
Другим способом является не создание Animal
общего, а метода Play
и ограничение этого на T : Animal
class Animal
{
public virtual void Play<T>(List<T> animals) where T : Animal { }
}
class Cat : Animal
{
public override void Play<T>(List<T> animals)
{
}
}
Наконец, если вы находитесь на C # 4 и вам нужно только перечислить список и не изменять его, проверьте ответ Эрика Липперта на IEnumerable<Animal>
.
использовать метод расширения Cast ()
so:
class Program
{
static void Main(string[] args)
{
Cat cat = new Cat();
cat.Play(new List<Cat>().Cast<Animal>());
}
}
Причиной этого является b / c .net 3.5 не поддерживает ковариацию, но 4.0 делает :)
cat.Play(new List<Cat>());
также не будет работать в 4 с существующим кодом.
– Anthony Pegram
15 September 2010 в 20:05
Все упоминают метод литья уже. Если вы не можете обновить до 4.0, способ скрыть приведение
class Cat : Animal
{
public override void Play(List<Animal> animal)
{
Play((List<Cat>)animal);
}
public virtual void Play(List<Cat> animal)
{
}
}
Это трюк IEnumable
и IEnumarable<T>
для GetEnumerator