作者:mobiledu2502880517 | 来源:互联网 | 2022-10-26 10:08
使用包含接口的if语句设置数组对象时,抛出InvalidCastException并需要理解为什么
我知道如何解决实际问题,我只是感到困惑为什么会这样。
请注意,customerOne和Two是接口(即ICustomer),而customers是“ Customer”的数组(不是接口)
只有当它是一个数组时,这才会出错,如果我尝试将单个对象设置为接口值,它将正常工作
Dim customerOne as ICustomer
Dim customerTwo as ICustomer
--- ^^这些被填充...然后我们创建一个数组:
Dim customers as Customer()
现在,奇怪的部分...
customers = {customerOne, customerTwo}
以上工作正常
customers = If(myBool, {customerOne,customerTwo}, {customerOne,customerTwo})
以上失败,并显示InvalidCastException
我希望If语句将返回与工作示例完全相同的值,因此不会引发InvalidCastException
有人知道这种行为的原因吗?
1> Steven Dogga..:
您的代码只能进行编译,因为您具有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无法自动执行类型转换。具体为什么,我不能说。
总是很好的答案和很好的解释