Вопрос по arrays, c#, casting, unsigned – http://msdn.microsoft.com/en-us/library/scekt9xw(VS.80).aspx

34

кто-нибудь прояснить C #is Ключевое слово, пожалуйста. В частности эти 2 вопроса:

Q1) строка 5; Почему это возвращает истину?

Q2) строка 7; Почему нет актерского исключения?

public void Test()
{
    object intArray = new int[] { -100, -200 };            

    if (intArray is uint[]) //why does this return true?
    {
        uint[] uintArray = (uint[])intArray; //why no class cast exception?

        for (int x = 0; x < uintArray.Length; x++)
        {
            Console.Out.WriteLine(uintArray[x]);
        }
    }
}

Описание MSDN не проясняет ситуацию. Это заявляет, чтоis вернет true, если любое из этих условий выполнено. (http://msdn.microsoft.com/en-us/library/scekt9xw(VS.71).aspx>MDSN Статья)

expression is not null.
expression can be cast to type.

Я не верю, что вы можете сделать правильный бросок int [] в uint []. Потому что:

А) Этот код не компилируется:

int[] signed = new int[] { -100 };
uint[] unsigned = (uint[])signed; 

Б) Выполнение приведения в отладчике дает ошибку:

(uint[])signed
"Cannot convert type 'int[]' to 'uint[]'"

Конечно, если бы строка 3 была int [] вместо object, она никогда не скомпилировалась бы. Что подводит меня к последнему вопросу, связанному с Q2.

В3) Почему в C # возникает ошибка приведения / преобразования в отладчике и компиляторе, но не во время выполнения?

Неправильно, это переполнение стека, вы имеете в виду «Где Джон Скит, когда он вам нужен?» ;) Ash
Где Эрик Липперт, когда он тебе нужен? William Holroyd
Проверьте мой ответ, я обновил ссылку на видео, которое, я думаю, объясняет основную проблему. Проверьте это! John Leidegren

Ваш Ответ

5   ответов
34

Ты не можешьнепосредственно бросить междуint[] а такжеuint[] в C #, потому чтоязык не верит, что какое-либо преобразование доступно. Тем не менее, если вы идете черезobject результат до CLI. Из раздела 8.7 спецификации CLI (надеюсь, я цитируюобмен электронной почтой у меня был на эту тему с Эриком Липпертом некоторое время назад):

Знаковые и беззнаковые целочисленные примитивные типы могут быть назначены друг другу; например, int8: = uint8 действителен. Для этого bool считается совместимым сuint8 и наоборот, что делаетbool := uint8 действителен, и наоборот. Это также верно для массивов со знаком и без знака целочисленных примитивных типов одинакового размера; например.,int32[] := uint32[] действует.

(Я не проверял, но я предполагаю, что этот вид преобразования ссылочного типа является действительным, что делаетis верните также истину.)

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

РЕДАКТИРОВАТЬ: Поскольку Марк удалил свой ответ, я связался с полной почтой от Эрика, как отправлено в группу новостей C #.

Звучит не слишком безопасно для меня. IllidanS4
ум = взорван ... Mehrdad
звучит как еще один кандидат на вопрос «что вы можете сделать в MSIL, чего не можете в c #». прямая конвекция без необходимости связываться с переменной object / Array, чтобы успокоить компилятор c # ShuggyCoUk
@ShuggyCoUk: Хороший звонок - обновлю мой ответ, со ссылкой на этот вопрос. Jon Skeet
4

с. Обратите внимание, что:

Массивы наследуются от System.Array.

Если Foo можно привести к Bar, тогда Foo [] можно применить к Bar [].

Для целей примечания 2 выше перечисления рассматриваются как их базовый тип: таким образом, E1 [] может быть приведен к E2 [], если E1 и E2 имеют общий тип.

Вы можете привести int к uint, но то, что он ведет себя так, очень странно. Visual Studio не распознает ничего из этого, даже часы, когда подключенный отладчик показывает только вопросительный знак «?».

Вы можете взглянуть наэтоПеремотайте вперед примерно на 10 минут и послушайте, как Андерс объясняет реализацию ко-варианта массива. Я думаю, что это фундаментальная проблема здесь.

1

Объявление intArray как «int [] intArray» вместо «object intArray» позволит компилятору подобрать недопустимое приведение C #. Если вам абсолютно не нужно использовать объект, я бы использовал этот подход.

Re Q2, Q3:

Во время выполнения вы пытались обернуть актерский состав впроверено блок?

Из этой статьи в MSDN:

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

...

По умолчанию эти неконстантные выражения не проверяются на переполнение во время выполнения, и они не вызывают исключений переполнения. Предыдущий пример отображает -2,147,483,639 как сумму двух натуральных чисел.

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

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

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

[Обновление] После тестирования этого кода я обнаружил, что использование объявления типа объекта вместо int [], по-видимому, обходит стандартный синтаксис приведения в C # независимо от того, включен флажок или нет.

Как сказал JS, когда вы используете объект, вы связаны правилами CLI, и они, очевидно, позволяют этому происходить.

Re Q1:

Это связано с вышеизложенным. Короче говоря, поскольку приведение к действию не вызывает исключение (на основе текущей настройки переполнения). Является ли это хорошей идеей, это другой вопрос.

Из MSDN:

Выражение «is» оценивается как true, если предоставленное выражение не является нулевым, и предоставленный объект может быть приведен к предоставленному типу, не вызывая исключение.

Нет, проверил, не ловит это, на удивление. Отладчик полностью сбит с толку содержимым (показывает только? Для элементов в инспекторе), и получение значения возвращает завернутое значение. Simon Buchan
Там внизу. (вероятно, скоро будет там :) Simon Buchan
Но это не отвечает на его первый вопрос: «почему (intArray is uint [])» Ed S.
Такое же поведение в моем тесте. Где Джон Скит, когда он тебе нужен? Ash
0

Я пытаюсь нанести удар в этом.

Во-первых, документация гласит: «Проверяет, совместим ли объект с данным типом». В нем также говорится, что ЕСЛИ тип слева является «castable» (вы можете преобразовать без исключения) в тип справа, и выражение оценивается как ненулевое, ключевое слово is будет оцениваться какtrue.

Посмотрите на Джона Скита для другого ответа. Он сказал это более красноречиво, чем я мог. Он прав, если преобразование доступно, оно примет ваш синтаксис, вы могли бы впоследствии написать свой собственный, но в этой ситуации это может показаться излишним.

Ссылка:http://msdn.microsoft.com/en-us/library/scekt9xw(VS.80).aspx

0

я все еще немного неясен в деталях, но я полагаю, что тип CLR всех массивов - просто System.Array, с дополнительными свойствами Type для поиска типа элемента. «is», вероятно, просто не учитывал это в CLR v1, и теперь должен поддерживать это.

Это не работает в(uint[])(new int[]{}) Вероятно, это связано с тем, что компилятор C # (а не среда CLR) может выполнять более строгую проверку типов.

Кроме того, массивы просто небезопасны:

Animal[] tigers = new Tiger[10];
tigers[3] = new Elephant(); // ArrayTypeMismatchException

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