The_Unknown_Member Ответов: 3

C# почему здесь не требуется явное приведение?


Как этот код работает без явного приведения?
<pre lang="c#">static void Main()
        {
            IList<Dog> dogs = new List<Dog>();
            IEnumerable<Animal> animals = dogs;
        }


Я говорю об этой строке: "IEnumerable<animal> animals = dogs;"
Здесь вы можете видеть, что я могу передать переменную dogs без явного приведения. Но как это возможно? Почему компилятор позволил мне это сделать? Разве я не должен сначала сделать гипс вот так:

"Интерфейс IEnumerable&ЛТ;животное&ГТ; животные = (список<собаки> В) собаки;"
Код будет работать с явным приведением и без явного приведения, но я не могу понять, почему он позволил мне назначить собак ссылочной переменной animals без явного приведения.

Что я уже пробовал:

Пытаюсь понять, что происходит с кодом.

3 Ответов

Рейтинг:
2
Рейтинг:
1

Christiaan van Bergen

Привет,

Это работает, потому что, вероятно, класс Dog является производным от класса Animal. Превращение собаки в животное.

public class Animal{}
public class Dog : Animal {}

Это значит, что в коллекцию животных мы всегда можем поместить собаку.

Все собаки-животные, но не все животные-собаки.
А теперь, если мы представим вам кошку ...
public class Cat : Animal {}
Мы также можем вставить эту кошку в коллекцию животных. Потому что это животное.
Однако мы не сможем поместить просто любое животное в коллекцию собак, потому что это означало бы, что мы могли бы просто поместить туда кошку. Вот почему нам нужно было бы бросить объект собаке, чтобы сделать это.
var dog = new Dog();
var cat = new Cat();
var animals = new List<Animal>();

animals.Add(dog); //works
animals.Add(cat); //works

var dogs = new List<Dog>();
dogs.Add(dog); //works
dogs.Add(cat); //fails


ХТ христиан


Рейтинг:
0

OriginalGriff

Предполагая, что у вас где-то есть такой код:

public class Animal { ... }
public class Dog : Animal { ... }

Тогда вы знаете, что Собака - это животное, поэтому вы можете назначить экземпляр собаки любой переменной, которая может содержать собаку или животное:
Dog dog = new Dog();
Animal animal = dog;
И вы, наверное, знаете, что-то IList&ЛТ;Т> включает в себя интерфейс IEnumerable&ЛТ;П&ГТ; среди других интерфейсов: Интерфейс IList<T> (System.Коллекции.Общий)[^]
Таким образом, любая переменная, которая может содержать IEnumerable<T>, может содержать экземпляр любого экземпляра класса, который ее реализует, и IList<T> это делает.
Поэтому, если подчиненный класс T также совместим, приведение не требуется, так как тип вообще не меняется.


The_Unknown_Member

Но ссылочная переменная, указывающая на список собак, - это интерфейс "IList<dog>", Поэтому я должен сделать явное приведение, чтобы назначить список ссылке IEnumerable<animal & gt;. Но на самом деле это работает??
Смотрите этот пример:
статический недействительным Главная()
{

IAnimal a = новая собака();
Кора(а);

}

статический недействительным гавкать(собака д)
{
Приставка.WriteLine("Баау баау :@@@");
}


"Bark(a);" этот код не будет работать, если я не приведу аргумент явно к Dog.

OriginalGriff

Это работает, потому что Собака - это животное, но ваш "новый код" не работает, потому что не каждое животное-Собака (некоторые могут быть кошкой, другие - лошадью).
Когда вы пишете это:

static void Bark(Dog d)

Вы говорите методу лая, что он должен принимать только параметры собаки.
Если бы ваш код работал, я мог бы сделать это:
IAnimal a = new Dog();
Bark(a);
a = new Horse();
Bark(a);

И тогда метод потерпит неудачу во время выполнения, потому что класс Horse не конвертируется в Dog (за исключением того, что он идет через "собачий корм", конечно...)
Подумайте об этом:
Если ваш метод сделал что-то специфичное для собаки с этим параметром:
static void Bark(Dog d)
{
d.Fetch(myStick);
}
и вы можете передать его любому животному, тогда что произойдет, когда вы пройдете мимо экземпляра кошки и попытаетесь научить его приносить палку?