Ваш код компилируется только потому, что у вас есть Option Strict Off
, что позволяет определенным ошибкам проскользнуть под RADAR во время компиляции и обнаруживаться только через исключения во время выполнения.Если вы включите Option Strict On
(что я, и большинство других, предложили бы вам сделать), событие, которое эта строка не компилирует:
customers = {customerOne, customerTwo}
Ошибка, которую он дает:
BC30512 Option Strict On запрещает неявное преобразование из 'ICustomer' в 'Customer'
Причина этого заключается в том, что выражение {customerOne, customerTwo}
вычисляется в массив из ICustomer
объектов, поскольку этотип переменных.Во время компиляции невозможно, чтобы компилятор знал, что эти две переменные определенно будут ссылаться на объекты Customer
, поскольку теоретически они могут ссылаться на любой тип объекта, который реализует интерфейс.Поэтому лучшее, что он может сделать, - это определить тип массива на основе переменных, заданных в его инициализаторе.
Итак, это выражение оценивается как массив ICustomer()
, но переменная, которой вы пытаетесь присвоить его, - это массив Customer()
.Поскольку Customer
является более конкретным, чем ICustomer
, это назначение не разрешается автоматически.Чтобы получить его для компиляции, вам нужно явно привести его.Либо вы можете привести элементы в инициализаторе массива, чтобы он вычислялся к нужному типу массива:
customers = {DirectCast(customerOne, Customer), DirectCast(customerTwo, Customer)}
Или, используя небольшой LINQ, вы можете позволить ему вычислять неправильный типмассив, а затем просто приведите весь массив:
customers = {customerOne, customerTwo}.Cast(Of Customer)().ToArray()
Однако ни один из этих параметров не является безопасным.Они оба допускают исключения проверки типов во время выполнения.Поэтому, если это вообще возможно, было бы лучше переписать ваш код таким образом, чтобы он позволял компилятору безопасно выполнять все проверки типов во время компиляции.Например, если вы измените переменную customers
на массив ICustomer
вместо массива конкретного типа Customer
, то он будет работать нормально:
Option Strict On
Public Module MyModule
Public Sub Main()
Dim myBool As Boolean = False
Dim customerOne As ICustomer = New Customer()
Dim customerTwo As ICustomer = New Customer()
Dim customers As ICustomer()
' Both of these lines compile fine because the arrays are all ICustomer()
customers = {customerOne, customerTwo}
customers = If(myBool, {customerOne, customerTwo}, {customerOne, customerTwo})
End Sub
Public Class Customer
Implements ICustomer
End Class
Public Interface ICustomer
End Interface
End Module
Насколькопричина, по которой троичный оператор If
сбрасывает его ... ну, это сложнее и идет мне в голову.Я стараюсь избегать использования Option Strict Off
любой ценой, поэтому, как именно это работает, я не знаю.Однако на высоком уровне оператор If
добавляет дополнительный уровень оценки и вывода типов в середине, что мешает попыткам VB сделать автоматическое преобразование типов за вас.Например, если вы сделаете это с Option Strict Off
, оно будет работать:
Dim customerOne As ICustomer = New Customer()
Dim customerTwo As ICustomer = New Customer()
Dim customers As Customer()
customers = {customerOne, customerTwo}
И если вы сделаете это, вы увидите, что то, что {customerOne, customerTwo}
оценивает, на самом деле является массивом ICustomer()
:
Dim customerOne As ICustomer = New Customer()
Dim customerTwo As ICustomer = New Customer()
Dim customers As Customer()
Dim temp As Object = {customerOne, customerTwo}
Console.WriteLine(temp.GetType().Name)
Но, если вы сделаете это, во время выполнения будет сгенерировано исключение:
Dim customerOne As ICustomer = New Customer()
Dim customerTwo As ICustomer = New Customer()
Dim customers As Customer()
Dim temp As Object = {customerOne, customerTwo}
customers = temp
Выдается исключение:
System.InvalidCastException: Невозможно привести объект типа 'ICustomer []' к типу "Customer []"
. Просто разделив его на два этапа, заставив сначала выполнить оценку входного массива, онвыходит из строя.Это будет работать только при создании массива и назначении переменной в той же команде.На самом деле, происходит сбой с тем же исключением, даже если вы указываете правильный тип для этой промежуточной переменной:
Dim customerOne As ICustomer = New Customer()
Dim customerTwo As ICustomer = New Customer()
Dim customers As Customer()
Dim temp As ICustomer() = {customerOne, customerTwo}
customers = temp
И это, по сути, то, что делает оператор If
.Он делится на два этапа, где оператор If
должен сначала оценить свои операнды, чтобы определить, к какому типу он сам относится, (например, к тому, что он возвращает, если он был методом).И этот дополнительный шаг в середине мешает VB автоматически выполнять преобразование типов.Конкретно почему, я не могу сказать.