2014-10-17 2 views
22

Вот какой-то код, который беспокоит меня каждый раз, когда я об этом думаю.VB vs C#: Почему это возможно?

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 

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

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

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

+1

Я включил оператор 'Option Strict' в сообщение, и он должен ограничивать преобразования типов в расширяющиеся преобразования и запрещать неявное типирование, но он все еще компилируется. – scottyeatscode

+4

@mellamokb, как показал OP, это работает даже с 'Option Strict On'. – jmcilhinney

+0

Это хороший момент. Согласно [этому сообщению в блоге] (http://www.owenpellegrin.com/articles/vb-net/converting-strings-to-numbers/) даже с 'Option Strict Off' он не должен допускать неявное преобразование строк, которые недействительными числовыми значениями, поэтому здесь должно произойти что-то еще.** РЕДАКТИРОВАТЬ **: я просто быстро это протестировал с LINQPad, и он, похоже, не компилируется ... где вы тестируете это, когда вы не получаете ошибки компилятора? – mellamokb

ответ

14

Это, по-видимому, идиосинкразия заявления For Each. Согласно документации, она оценивается в Runtime.

От Link:

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

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

+2

Отлично! Спасибо, Марк! – scottyeatscode

+1

Добро пожаловать, интересный вопрос. –

+8

Ничего себе - когда я думал, что видел все это до странности VB ... –

6

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

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 
+0

Как вы могли посмотреть, как этот код превратился в это? Я не могу сделать это в Reflector 8. – scottyeatscode

+0

Если у вас есть настольное приложение, вы можете перетащить исполняемый файл в дереве сборки. –

+0

Все выглядит очень читаемо для меня и в C#. Так выглядит декомпиляция после обфускации? – scottyeatscode

11

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

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

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

0

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

+1

Я обновил код, чтобы они были «строгими строковыми массивами». Код по-прежнему не показывает ошибок времени компиляции. Марк Холл, Бьорн-Роджер Крингша и Ханс Пассант уже предоставили более чем достаточно информации, чтобы объяснить, почему это происходит. – scottyeatscode

+0

На самом деле, если вы посмотрите на ответ Бьорна-Роджера Крингши, список строк в конечном итоге станет массивом строк. – scottyeatscode

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