Подтвердить что ты не робот

VB vs С#: Почему это возможно?

Вот какой код, который беспокоит меня каждый раз, когда я думаю об этом.

Option Strict On

Module Module1

    Sub Main()
        For Each i As Integer In New String() {"why", "is", "this", "tolerated?"}
            ' compiles just fine.
        Next
    End Sub

End Module

С# просто не разрешает преобразовывать строки в целые числа неявно.

class Program {
    static void Main(string[] args) {
        foreach (int i in new string[] {"that's", "better"}) {
            // will not compile, and for good reason.
        }
    }
}

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

4b9b3361

Ответ 1

Похоже, это идиосинкразия For Each. Согласно документации, она оценивается во время выполнения.

От ссылки:

Если для параметра Strict установлено значение On, сужение конверсий обычно вызывает ошибки компилятора. Однако в операторе For Each преобразования из элементов в группе в элемент оцениваются и выполняются во время выполнения, а ошибки компилятора, вызванные сужением конверсий, подавляются.

В следующем примере назначение m в качестве начального значения для n не компилируется, когда параметр Strict включен, потому что преобразование длинного в целое является сужающим преобразованием. Однако в инструкции For Each не сообщается об ошибке компилятора, даже если для присвоения номеру требуется такое же преобразование из Long в Integer. В операторе For Each, который содержит большое число, возникает ошибка времени выполнения, когда ToInteger применяется к большому числу.

Ответ 2

Microsoft извиняется за это в языковой спецификации, глава 10.9:

Текущий элемент итерации преобразуется в тип управляющей переменной цикла, даже если преобразование является явным, потому что нет удобного места для введения оператора преобразования в оператор. Это стало особенно трудным при работе с наиболее распространенным типом коллекции System.Collections.ArrayList, потому что его тип элемента - Object. Это потребовало бы отливок в большом количестве циклов, что мы чувствовали не идеально.

По иронии судьбы, дженерики позволили создать сильно типизированную коллекцию System.Collections.Generic.List(Of T), которая, возможно, заставила нас переосмыслить эту конструктивную точку, но для совместимости это не может быть изменено сейчас.

Ответ 3

В качестве дополнения к ответу Mark ответьте, как выглядит скомпилированный код vb.net. Как вы можете видеть, код компилируется в оператор For... Next, и ошибка возникает только во время выполнения при попытке конвертировать string to integer.

Dim VB$t_array$L0 As String() = New String() { "why", "is", "this", "tolerated?" }
Dim VB$t_i4$L0 As Integer
For VB$t_i4$L0 = 0 To VB$t_array$L0.Length - 1
    Dim i As Integer = Conversions.ToInteger(VB$t_array$L0(VB$t_i4$L0))
Next VB$t_i4$L0

Ответ 4

Я единственный, кто может видеть, что в коде VB массив представляет собой общий (вариант) массив, в то время как код С# содержит строгий массив строк?