如果我有两个类,并且在它们之间定义了显式类型转换,我是否应该无法将一个类的数组转换为另一个类的数组?
即。
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;
}
}
}
}
仅当源类型和目标类型之间存在引用转换时,转换才有效 - 换句话说,数组中的每个元素都可以用作任一类型,而不更改数据。
来自 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);
Eric Lippert 在他的博客上撰写了一系列关于协变和逆变的精彩文章。阅读时它们让我头疼,但每次我都会变得更聪明。似乎最能回答这个问题的帖子是
我建议浏览他的博客以获取相关帖子。
希望这有帮助
这是非法的,因为编译器不会自行假设您想要的是一个包含从苹果转换而来的橙子的新数组。
当存在从苹果到橙子的显式转换时,为什么它不假设它可以做到这一点?
首先,因为显式意味着代码应该专门请求它。例如,这仍然会失败:-
anOrange = anApple;
通过使用
explicit
关键字,您表示转换可用,但必须像这样显式请求:-
anOrange = (Orange)anApple;
其次,即使使用
implicit
关键字,这也是合法的:-
anOrange = anApple;
这并不意味着每个的整个数组都是如此。为什么设计者可以看到数组的元素类型具有隐式转换,因此从技术上讲可以创建一个新数组并执行所有转换?我不知道你得问他们。据猜测,这带来的好处是微乎其微的,特别是因为您已经发现了一种明确的单行替代方案。我想,开发、测试等(按照 Eric Lippert 的通常清单)的成本会相当高。
我更喜欢 System.Linq 中的扩展方法:
oranges = apples.Cast<Oranges>().ToArray();
编辑:
由于 Cast 不适用于隐式转换运算符,因此我将使用 select 来代替:
oranges = apples.Select(x => (Oranges)x).ToArray();
与您的代码的区别在于,这会创建一个新数组,而您的代码首先创建数组,然后复制强制转换的引用。