2016-07-25 3 views
1

C# 6.0 в двух словах Джозефом Альбахари и Бен Альбахари (O'Reilly).Ошибки времени выполнения Ковариации

Copyright 2016 Joseph Albahari and Ben Albahari, 978-1-491-92706-9.

состояния, на страницах 123-124, с относительно типа ковариации:

Массивы, по историческим причинам, типы массивов поддержки ковариации. Этот означает, что B [] может быть отлит до A [], если B-подклассы A (и оба являются ссылочными типами).

Например:

Bear[] bears = new Bear[3]; 
Animal[] animals = bears; // OK 

Недостатком этого повторного является то, что элемент назначения может не во время выполнения:

animals[0] = new Camel(); // Runtime error 

Что является причиной такой ошибки? Если вы назначаете экземпляр Bear в экземпляр Animal, будет вызвана ошибка времени выполнения? Я не понимаю, почему это нужно (разрешая такое задание, компилятор должен взять на себя ответственность, заявив «все в порядке, я позволю вам сделать с этим объектом все, что может сделать животное». Поскольку Медведь - это животное, это навлекает . никаких проблем

Я создал свой собственный сценарий, чтобы проверить выше:.

public class X 
{ 
    public int Num { get; set; } 

    public void Method_1() 
    { 
     Console.WriteLine("X"); 
    } 

    public virtual void Method_2() 
    { 
     Console.WriteLine(Num); 
    } 
} 

public class Y : X 
{ 
    public Y() 
    { 
     Num = 1000; 
    } 
} 

X[] arrayX = new X[] { new X { Num = 1000 }, new X { Num = 999 }, new X { Num = 51762 } }; 
Y[] arrayY = new Y[] { new Y { Num = 5 }, new Y { Num = 6 }, new Y { Num = 7 } }; 

X x = new X { Num = 1000 }; 
Y y = new Y { Num = 50 }; 

x = y; 

arrayX = arrayY; 

arrayX[2] = new Y { Num = 1 }; 

// will print 5,6,1 - no runtime errors faced 
foreach (var e in arrayX) 
    Console.WriteLine(e.Num); 

Я считаю, что этот фрагмент коды вышеописанным подражает пример книги - но с моим сниппета, нет ошибок во время выполнения

Что мне не хватает? Как animals[0] = new Camel(); должен был сбросить ошибку времени выполнения, как говорится в книге?

+1

Хотя массив 'animals' выглядит как массив животных, на самом деле это массив медведей. Вы не можете добавить верблюда в массив медведей (очевидно, медведи съели бы верблюда). В вашем примере есть животное (X) и медведь (Y), но отсутствует второй класс детей, например, верблюд. – juharr

ответ

4

В чем причина такой ошибки?

Потому что он пытается сохранить Camel в массив с типом во время выполнения Bear[]. Массив типа Bear[] может только хранить ссылки на экземпляры Bear или подклассы. Тип компиляции времени Animal[] только говорит, что может быть в состоянии хранить Camel ссылки, и что любая ссылка вы получите из массива, безусловно, будет Animal экземпляра или подкласса.

Ваш пример отличается. Когда мы снимаем все свойства и т.д. (которые не имеют никакого отношения) вы получили:

X[] arrayX = new Y[3]; 
arrayX[2] = new Y(); 

Это нормально - вот хранить ссылку на Y объект в массиве с типом исполнения, время Y[]. Нет проблем.

Чтобы продемонстрировать такую ​​же проблему, как книги, вам потребуется третий класс:

class Z : X {} 

X[] arrayX = new Z[3]; 
arrayX[2] = new Y(); // Bang - can't store a Y reference in a Z[] 
+0

@Veverke: Я не уверен, что вы имеете в виду, но теперь я смотрю на ваш более привлекательный пример. –

+0

Привет, Джон, мой вопрос об утверждении книги «животные [0] = новый верблюд(); // Ошибка выполнения. – Veverke

+3

@Veverke Вот что ответил Джон. – Servy

1

Ваш пример с X и Y совершенно отличается от того, из книги. Если вы хотите подражать одному из книги, создайте абстрактный базовый класс X, а затем сделайте Y и Z из него. Затем поиграйте с ним. Одно из книги следует, что:

class Program 
{ 
    static void Main(string[] args) 
    { 
     Bear[] bears = new Bear[3]; 
     Animal[] animals = bears; 
     animals[0] = new Camel(); //will throw on runtime 
    } 
} 

public abstract class Animal { } 

public class Camel : Animal { } 

public class Bear : Animal { } 

Как Джон уже говорилось, тип времени выполнения animals будет Bear[], который просто не может хранить экземпляр Camel. Также, пожалуйста, обратите внимание, что это возможная ошибка ковариантного преобразования массива, но этого не будет для других коллекций, как List:

 List<Bear> bearsList = new List<Bear>(); 
     List<Animal> animalsList = bearsList; //won't compile because of this error 
     animalsList[0] = new Camel(); 
1

В следующей строке:

Animal[] animals = bears; 

Вы просто скрывается ваш Bear[] - Animal[].

Обратите внимание, что я говорю , скрывая, потому что вы на самом деле не создаете новый массив.

Оба bears и animals указывают на то же Bear[], единственное отличие состоит в том, что animals скрывает, что ссылка в качестве Animal[].


Компилятор этого не знает.

Для компилятора, если вы хотите сохранить Dolphin или Lion на animals, это позволит вам сделать это, так как все эти элементы типа Animal.


Времени, однако, будет жаловаться.

С animals скрывает Bear[], добавив Camel, чтобы он не допускался.

Хотя Bear и Camel оба наследуют от Animal, они представляют собой два разных типа.

0

Для этого кода:

Animal[] bears = new Bear[3]; 

Если вы установили Resharper в вашем VS, это дает такое же предупреждение:

Co-вариант преобразования массива из Медведицы [] для животных [] может вызвать время выполнения исключение при операции записи.

Если вы используете Generic такие как IList:

IList<Animal> bears = new List<Bear>(); 
bears.Add(new Camel()); 

первая строка не позволит вам компилировать, который является более безопасным, предотвращает его от возможного исключения времени выполнения.

Смежные вопросы