如果我有两个类,并且已经定义了它们之间的显式类型转换,那么我是否应该无法将一个数组转换为另一个数组?
即
using System;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Apple ted = new Apple() { Variety = Apple.EVariety.RedEllison };
Orange bob = (Orange)ted; // explicit type conversion
Apple[] apples = new Apple[] { ted };
Orange[] oranges = new Orange[1];
//oranges = apples; // why is this illegal ?
// is this better ?
oranges = Array.ConvertAll<Apple, Orange>(apples, new Converter<Apple, Orange>(p => (Orange)p));
}
class Apple
{
public enum EVariety { RedEllison, GrannySmith }
public EVariety Variety;
}
class Orange
{
enum EColour { Unknown, Red, Green }
EColour Colour;
public static explicit operator Orange(Apple apple)
{
Orange result = new Orange();
result.Colour = apple.Variety == Apple.EVariety.RedEllison ? result.Colour = EColour.Red : result.Colour = EColour.Green;
return result;
}
}
}
}
谢谢, 罗斯
答案 0 :(得分:4)
只有在源类型和目标类型之间存在引用转换时,转换才有效 - 换句话说,即数组中的每个元素都可以用作任何一种类型的转换,而不会更改为数据。
从C#规范,第6.2.4节(显式引用转换):
显式引用转换 是:
...
- 从具有元素类型SE的数组类型S到具有的数组类型T. 元素类型TE,提供了所有 以下是真实的:
- S和T仅在元素类型上有所不同。换句话说,S和T有 相同数量的维度。
- SE和TE都是参考类型。
- 从SE到TE存在明确的参考转换。
在我看来,Array.ConvertAll
绝对是走到这里的方式,但你应该能够使用类型推断来使它更好:
oranges = Array.ConvertAll(apples, p => (Orange)p);
答案 1 :(得分:2)
Eric Lippert在他的博客上撰写了一系列关于协方差和逆变的优秀帖子。他们在阅读时会让我的头部受伤,但每次我都会变得更聪明。似乎最能回答这个问题的帖子是
why-is-covariance-of-value-typed-arrays-inconsistent
我建议浏览他的博客以获取相关帖子。
希望这有帮助
答案 2 :(得分:0)
我更喜欢System.Linq中的扩展方法:
oranges = apples.Cast<Oranges>().ToArray();
编辑:
由于Cast不能与隐式转换运算符一起使用,我会改用select:
oranges = apples.Select(x => (Oranges)x).ToArray();
代码的不同之处在于,这会创建一个新数组,而您的数组首先创建数组,然后复制已转换的引用。
答案 3 :(得分:0)
这是非法的,因为编译器不会认为你想要的是一个包含从苹果转换的橙子的新数组。
为什么它不能假设它在从苹果到橙子的显式转换存在时能够做到这一点?
首先,因为显式意味着代码应该专门请求它。例如,这仍然会失败: -
anOrange = anApple;
使用explicit
关键字,您说转换可用,但必须明确请求,如下所示: -
anOrange = (Orange)anApple;
其次,即使使用了implicit
关键字,这也是合法的: -
anOrange = anApple;
这并不意味着每个阵列的整个阵列都是如此。为什么这样,设计人员可以看到数组的元素类型具有隐式转换,所以从技术上讲,可以创建一个新数组并执行所有转换?我不知道你不得不问他们。猜测一下,这会产生的好处是微不足道的,特别是因为你已经发现了一个明确的单线替代方案。开发,测试等的成本(Eric Lippert通常的列表)将是我想象的非常高。