Приведение типов Generi c - Почему прямое приведение с круглыми скобками "()" дает ошибку компиляции, но приведение с использованием ключевого слова "как" работает? - PullRequest
0 голосов
/ 22 февраля 2020

Мне нужно было преобразовать обобщенный тип c, производный от UnityEngine.Object, в UnityEngine.AudioClip, но у меня постоянно возникала эта ошибка:

Сообщение об ошибке:

ошибка CS0030: невозможно преобразовать тип 'T []' в 'UnityEngine.AudioClip []'

И я был сбит с толку, причина AudioClip происходит от Object, так что это не должно быть проблемой.

Таким образом, Пример кода 1 ниже - это мой код, когда я получил ошибку. Затем я решил ошибку, изменив код на Пример кода 2 .

Итак, мой вопрос:

Почему прямой приведение (ie. с использованием круглых скобок) НЕ работает, но приведение с использованием as -ключевого слова сработало?

Я хочу понять, почему Пример кода 2 работает. Я посмотрел на ответ " Direct Casting vs 'as'? " - но я не понимаю, как это будет связано с этой проблемой. Поэтому любая помощь или объяснение того, почему это работает так, как оно есть, будет очень признательна.


Пример кода 1: прямое приведение (ie. С использованием скобок)

private void UpdateAudioClipsOnDragAndDrop<T>(T[] draggedObjects) where T : UnityEngine.Object
{
    audioClips = (AudioClip[])draggedObjects;
}

Пример кода 2: приведение с использованием "as "- ключевое слово

private void UpdateAudioClipsOnDragAndDrop<T>(T[] draggedObjects) where T : UnityEngine.Object
{
    audioClips = draggedObjects as AudioClip[];
}

Вот также скриншот ошибки в Visual Studio

Ответы [ 2 ]

0 голосов
/ 22 февраля 2020

И я был сбит с толку, потому что AudioClip происходит от Object, так что не должно быть проблем с приведением к нему.

Да, приведение с Object[] на AudioClip[] нормально (по крайней мере, во время компиляции), но вы делаете здесь приведение от T[] к AudioClip[].

Обобщенное c ограничение T: Object не означает T == Object. Это означает, что T является подклассом Object. Так что это может быть случай, когда T == AudioClip, или T == Component, или T == GameObject. Надеюсь, вы согласитесь, что нет явного преобразования между GameObject[] и AudioClip[]. Если вы не согласны, вот язык spe c:

Явные ссылки:

  • ...
  • От array_type S с типом элемента SE до array_type T с типом элемента TE при условии, что выполняются все следующие условия:
    • S и T отличаются только типом элемента. Другими словами, S и T имеют одинаковое количество измерений.
    • Оба SE и TE являются ссылочными типами.
    • Существует явное преобразование ссылок из SE в TE.

Есть ли явное ссылочное преобразование из T в AudioClip тогда? В этом разделе нет такого преобразования, поэтому нет.

Оператор as, однако, работает следующим образом (снова отрывок из language spe c ):

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

В операции вида E as T, E должно быть выражением, а T должно быть ссылочным типом, a Параметр типа известен как ссылочный тип или обнуляемый тип. Кроме того, по крайней мере одно из следующего должно быть истинным, иначе возникнет ошибка времени компиляции:

  • Идентификатор, неявная обнуляемая, неявная ссылка, бокс, явная обнуляемая, явная ссылка или преобразование без распаковки существует от E до T.
  • Тип E или T - открытый тип.
  • E - нулевой литерал .

Важным моментом является то, что as не выдаст ошибку, если тип E - это открытый тип . Согласно этот раздел спецификации c, T[] является открытым типом, потому что это тип массива параметра типа.

Почему ли дизайнеры языка это так? Вы должны попросить их узнать истинный ответ! :) Я предполагаю, что они хотели иметь более строгий тип кастинга и менее строгий тип, который не создает sh, когда он терпит неудачу.


В конце концов, даже если вы используется as, это заданное c преобразование все равно будет неудачным (audioClips будет нулевым), если T == AudioClip.

0 голосов
/ 22 февраля 2020

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

В первом В случае прямого приведения вы говорите компилятору, что это ДОЛЖЕН быть тип AudioClip [], а во втором - МОЖЕТ быть - если это не так, то результатом будет null.

Вы можете дать подсказку компилятору, как вы уже сделали, используя ключевое слово where и указав класс T, так что даже первый случай будет не проблематичным c для компилятора.

...