Утверждение.Равно пытается привести ushort? к ‘string’

#c# #nullable #xunit.net #ushort

#c# #обнуляемый #xunit.net #ushort

Вопрос:

Когда a ushort? передается Assert.Equal , он пытается привести два аргумента string . Это отлично работает для int? . Если я изменю код на ushort test = 10; или Assert.Equal((ushort)10, test); или Assert.Equal(10, (ushort)test); , он будет работать нормально. В чем причина этого? Может ли это быть из ushort -за того, что и то, и другое char составляет 2 байта и Assert.Equal неявно пытается обработать ushort? как строку?

введите описание изображения здесь

Комментарии:

1. Какой конкретный Assert.Equal вызов вы ожидаете от него (чтобы мы могли объяснить, почему он его не выбирает)? github.com/xunit/assert.xunit/blob/main/EqualityAsserts.cs

2. Короткий ответ заключается в том, что общее разрешение не будет / не может найти тип T, который принимает оба int и ushort? . Так он знает, что ushort может быть передан как int или как int? может быть передан как int — но он не «знает», что оба ushort? и int может быть передан как int? .

3. 10 есть int . 10L было бы long , 10d было бы double и 10m было бы decimal . Похоже, что для (u) short нет литерала. И, по-видимому, не существует неявного способа приведения int к ushort? . Итак, это утверждение пытается найти другой способ сравнения значений. По-видимому, пытаясь вызвать метод, который ожидает две строки.

4. Вы можете повторить это с небольшим примером самостоятельно, если хотите — dotnetfiddle.net/NoqNDD .

5. Я обновил свой ответ.

Ответ №1:

Обратите внимание, что, хотя существует неявное преобразование из 10 в ushort?

 ushort? foo = 10;
 

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


Группа Equal методов имеет общие методы, подобные тому, который вы пытаетесь вызвать. Таким образом, перед началом разрешения перегрузки происходит вывод типа.

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

В этом случае вывод типа фактически завершается неудачей для всех общих перегрузок, поэтому они не участвуют в разрешении перегрузки. Equal(string, string) это одна из перегрузок, которые делают. Вот почему сообщение об ошибке связано с перегрузкой строки.

Почему вывод типа завершается ошибкой? Потому что нет неявного преобразования из int в ushort? или из ushort? в int . Вывод типа заботится только о типах аргументов, параметров и параметров типа. Его не волнует, являются ли аргументы постоянными выражениями или чем-то подобным, поэтому вышеупомянутое неявное преобразование постоянных выражений неприменимо. Я рекомендую вам выполнить процесс вывода типа в спецификации. Это очень весело 🙂

Смотрите Ссылки На «тип Ei » здесь:

Для каждого из аргументов метода Ei :

  • […]
  • В противном случае, если Ei имеет тип U и xi является параметром значения, тогда делается вывод с нижней границей от U to Ti .
  • […]

Сравните это с тем, как он ссылается на «аргумент», а не на «тип аргумента» в разрешении перегрузки:

Для каждого аргумента in A режим передачи параметра аргумента (т.Е. Значение, ref , или out ) идентичен режиму передачи параметра соответствующего параметра, и

  • для параметра значения или массива параметров существует неявное преобразование из аргумента в тип соответствующего параметра, или
  • […]

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

Причина, по которой приведение 10 к ushort или byte работает, заключается в том, что существует неявное преобразование между from ushort to ushort? и from byte to ushort? . Это делается с помощью неявного преобразования с нулевым значением.

Комментарии:

1. @mjwills Я переписал весь ответ. Надеюсь, на этот раз я понял это 🙂

2. Итак, грубо говоря, это будет работать, если значение с нулевым значением является «более широким», но не «более узким»?

3. @mjwills да. Это то, что я нашел.

4. @Sweeper, спасибо, теперь это имеет смысл 🙂

5. @KeepCalmAndCode Если вы считаете, что мой ответ отвечает на ваш вопрос, пожалуйста, подумайте о том, чтобы принять его, нажав на эту галочку!