13

Этот код:Почему Resharper говорит: «Ковариантное преобразование массива из строки [] в объект [] может вызвать исключение во время выполнения при операции записи» с помощью этого кода?

comboBoxMonth.Items.AddRange(UsageRptConstsAndUtils.months.ToArray()); 

public static List<String> months = new List<String> 
{ 
    "Jan", 
    "Feb", 
    "Mar", 
    "Apr", 
    "May", 
    "Jun", 
    "Jul", 
    "Aug", 
    "Sep", 
    "Oct", 
    "Nov", 
    "Dec" 
}; 

Включает R # скряга, как с жалобой, «Ко-вариант преобразования массива из строки [] объекта [] может вызвать исключение во время выполнения операции записи на».

На самом деле этот код отлично работает - поле со списком заполняется значениями месяца; что такое Resharper, и что я могу сделать, чтобы успокоить его сомнения?

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

+2

Я предполагаю, что способ обойти это будет использовать «Список » вместо «Список ». –

ответ

21

Метод comboBoxMonth.Items.AddRange ожидает параметр object[]. months.ToArray() является string[]. Листинг от string[] до object[] действителен, но если метод пытается изменить элементы массива, вы получите ошибки во время выполнения. В этом случае это не так, поэтому вы можете игнорировать предупреждение.

Если это вас раздражает, вы можете использовать ToArray<object>()

comboBoxMonth.Items.AddRange(UsageRptConstsAndUtils.months.ToArray<object>()); 

Он вернется object[] и не будут нужны не литая.

+1

Что вы подразумеваете под *, если метод пытается изменить элементы массива *? Изменение элемента, уже находящегося в массиве, не должно быть проблемой. –

+2

@YuvalItzchakov: Если метод пытается присвоить банану элементу один из массива объектов, который действительно представляет собой массив строк, тогда во время выполнения произойдет сбой. Люди разумно ожидают, что назначение банана в массив объектов будет успешным, но это может и не быть. –

+0

@EricLippert Да, я понимаю, и именно это я попытался передать в своем ответе. Но я думаю, что в предложении есть двусмысленность, в которой говорится, что изменение существующих элементов приведет к исключению во время выполнения. –

13

Пример для демонстрации проблемы:

void Main() 
{ 
    Animal[] animals = new Girafee[2]; 
    animals[0] = new Zebra(); 
} 

public class Animal { } 
public class Girafee : Animal { } 
public class Zebra : Animal { } 

Это будет бросать ArrayTypeMismatchException во время выполнения.

R # в основном намекая вас о возможной проблеме того, что вы назначая string[] к object[], который полностью разрешен компилятору, но может привести к исключению времени выполнения, если объект, который разделяет один и тот же базовый класс, назначается массиву, который уже указывает на другой тип (как в моем примере мы фактически указываем массив girafee). Соотношение между массивами нарушается в том смысле, что оно не дает вам безопасности во время компиляции, которую вы получаете с помощью дженериков.

Эрик Lippert говорит об этом в Covariance and Contravariance in C#, Part Two: Array Covariance:

К сожалению, этот конкретный вид ковариации нарушается. Это было , добавленное в CLR, потому что Java требует этого, и разработчикам CLR требуется , чтобы иметь возможность поддерживать Java-подобные языки. Затем мы добавили его в C#, потому что он был в CLR. Это решение было довольно противоречивым в времени, и я не очень этому доволен, но мы ничего не можем сделаем об этом сейчас.

Почему это сломано? Потому что всегда должно быть законно помещать черепаху в массив животных. С помощью ковариации массива на языке и времени выполнения вы не можете гарантировать, что массив животных может принять черепаху , потому что хранилище резервных копий может быть массивом Жирафы.

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