Могу ли я передать коллекцию более конкретных типов, требуется ли сбор более общих типов? [Дубликат]

Нет, селектор «предыдущего сиблинга» отсутствует.

В соответствующей заметке ~ используется для общего брака-последователя (это означает, что элемент появляется после этого, но не обязательно сразу после) и является селектором CSS3. + для следующего родного брата и является CSS2.1.

См. Комбинированный смежный блок-класс из Селектора уровня 3 и 5.7 Смежные селекторные ролики из Каскадные таблицы стилей Уровень 2 Редакция 1 (CSS 2.1) Спецификация .

22
задан santosh singh 15 September 2010 в 19:51
поделиться

5 ответов

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

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>, чтобы добавить собаку к тому, что на самом деле является списком кошек.

45
ответ дан Eric Lippert 19 August 2018 в 06:25
поделиться
  • 1
  • 2
    @Dykam: Это не так. Я пытался следовать структуре кода, изложенной в оригинальном плакате. – Eric Lippert 17 September 2010 в 19:08
  • 3
    Ах я вижу. По какой-то причине я не связывал два фрагмента. – Dykam 18 September 2010 в 16:41
  • 4
    плюс один для сохранения моих кошек в безопасности – Sayka 4 March 2017 в 16:27

Вы могли бы сделать несколько вещей. Например, элементы списка относятся к 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>.

13
ответ дан Anthony Pegram 19 August 2018 в 06:25
поделиться
  • 1
    – Scott Chamberlain 15 September 2010 в 20:00
  • 2
    Также +1 для указания, что вы, вероятно, должны использовать IEnumerable для типа параметра, а не List – Joel Coehoorn 15 September 2010 в 20:05
  • 3
    Я не понимаю, что последний бит; почему класс Cat имеет метод с параметром типа Cat? Разве это не слишком запутанно, иметь два типа с одним и тем же именем внутри одной и той же декларации? – Eric Lippert 15 September 2010 в 22:38
  • 4
    Что ж, это о нем. Я становлюсь водопроводчиком. – Anthony Pegram 16 September 2010 в 01:05
  • 5
    Водопроводчики зарабатывают хорошие деньги, а аутсорсинг сантехники для зарубежных компаний невозможно. Мне гораздо удобнее работать с электричеством, чем вода. Если я когда-нибудь заболею этой работой по сантехнике, возможно, я это сделаю. – Eric Lippert 16 September 2010 в 07:07

использовать метод расширения 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 делает :)

3
ответ дан Jose 19 August 2018 в 06:25
поделиться
  • 1
    Причина не в том. cat.Play(new List<Cat>()); также не будет работать в 4 с существующим кодом. – Anthony Pegram 15 September 2010 в 20:05
10
ответ дан Justin Niessner 19 August 2018 в 06:25
поделиться

Все упоминают метод литья уже. Если вы не можете обновить до 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

2
ответ дан Scott Chamberlain 19 August 2018 в 06:25
поделиться
Другие вопросы по тегам:

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