有一天我偶然发现了这个奇怪的表情,我觉得它应该有效。
var attributes = (new object[]
{
new SomeClass(),
}) as SomeBaseClass[];
在此代码段中,SomeClass
会继承SomeBaseClass
,因此我认为演员表应该有效。
但事实上,attributes
始终评估为null
。如果我使用强制转换形式,我将获得InvalidCastException
。
答案 0 :(得分:4)
object[]
数组可以存储和检索任何内容。因此,不可能将其强制转换为更多派生类型的数组。这在Cast List<X>
to List<Y>
中解释。
显示还有解决方法:
SomeType[] typedObjects = someObjectArray.Cast<SomeType>().ToArray();
请注意,如果someObjectArray
中的任何项目无法转换为SomeType
,则会引发异常。
答案 1 :(得分:3)
这是正确的行为。看一下as
运算符的规范:
as运算符就像一个强制转换操作。但是,如果无法进行转换,则返回null而不是引发异常。请考虑以下示例:
expression as type
代码等同于以下表达式,只是表达式变量只被计算一次。
expression is type ? (type)expression : (type)null
现在从T
到U
的转换不意味着从T[]
转换为U[]
:as
运算符对于数组(或其他集合)而言,它不是一个智能运算符,它将执行元素明确as
。它仅检查是否存在从object[]
到SomeClass[]
的转换,并且没有,因此它会回退到默认行为:return null
。
考虑Mono的C#交互式shell的以下csharp
输出:
$ csharp
Mono C# Shell, type "help;" for help
Enter statements below.
csharp> public class Foo {}
csharp> var attributes = new object[] {new Foo(),new Foo(),};
csharp> (Foo[]) attributes
System.InvalidCastException: Cannot cast from source type to destination type.
at <InteractiveExpressionClass>.Host (System.Object& $retval) [0x00000] in <filename unknown>:0
at Mono.CSharp.Evaluator.Evaluate (System.String input, System.Object& result, System.Boolean& result_set) [0x00000] in <filename unknown>:0
at Mono.CSharpShell.Evaluate (System.String input) [0x00000] in <filename unknown>:0
答案 2 :(得分:3)
通常你不应该将任何类型的数组转换为另一种类型,这样做是不好的做法。为了向后兼容,C#具有array covariance,它允许在相反方向上进行转换,但不允许在您想要的方向上进行转换。要正确转换数组,您必须创建另一个数组,如this stackoverflow post:
所示var attributes = (new object[]
{
new SomeClass(),
}).Cast<SomeBaseClass>().ToArray();
考虑以下示例:
class A {}
class B : A {}
...
var array_a1 = new A[] { new A(); };
var array_b1 = (B[])array_a; // This is error #1
var array_b2 = new B[] { new B(); };
var array_a2 = (A[])array_b2;
array_a2[0] = new A(); // This is error #2
在错误#1 的情况下,可以清楚地看到array_b1
不能是A[]
的有效视图,因为它在读取时可能包含A类对象。这是InvalidCastException
的运行时错误,发生在演员阵容时。
如果是错误#2 ,array_a2
是array_b2
的有效视图,但仅供阅读。由于array covariance允许转换本身,但是尝试在其中放置类型A的元素将导致运行时ArrayTypeMismatchException
,因为它会导致array_b2
具有类型A的元素为了确保这种类型的安全性,CLR必须对阵列分配进行运行时类型检查,这会影响性能。