C#中的隐式数组转换

我有以下类定义了隐式转换运算符:

class A { ... } class B { private A m_a; public B(A a) { this.m_a = a; } public static implicit operator B(A a) { return new B(a); } } 

现在,我可以隐含地将A转换为B.

但为什么我不能隐含地将A []强制转换为B []?

 static void Main(string[] args) { // compiles A a = new A(); B b = a; // doesn't compile A[] arrA = new A[] {new A(), new A()}; B[] arrB = arrA; } 

谢谢,Malki。

正如Mehrdad Afshari所提到的那样,你在运气方面做得不好。 你必须明确,它将涉及一个数组副本。 值得庆幸的是,您可以使用单行代码来实现:

 arrB = arrA.Cast().ToArray(); 

虽然如果你只想在foreach语句中迭代arrB ,你可以通过省略ToArray()来避免复制

数组协方差仅适用于引用类型和inheritance层次结构(请注意,它不是表示更改转换:只是一组具有相同大小的指针解释不同。)它不适用于值类型和用户定义的转换。

ConvertAll

只是为了明确,这是你如何使用ConvertAll。

class B具有名为m_a class A成员的情况下,执行以下操作:

 B[] arrB; A[] arrA = Array.ConvertAll(arrB, b => b.m_a); 

如果class B有一些您需要操作的成员数据,然后才能返回A类对象(例如将一堆数值转换为字符串描述),请执行以下操作:

 class B { public static A makeAfromB(B b) { // Do something with B data... A a = new A("data made from B data") return a; } // rest of class B implementation ... } // somewhere else in your code... A[] arrA = Array.ConvertAll(arrB, new Converter(B.makeAfromB)); 

您还可以使用Lambda函数:

 A[] arrA = Array.ConvertAll(arrB, new Converter( delegate(B b) { // Do something with B data, though object b is const A a = new A("data made from B data") return a; })); 

如果ConvertAll可以使用隐式运算符进行转换会很好,但我还没弄明白如何做到这一点。

@Randolpho @bottlenecked

对于您只想迭代并且不想复制的情况,使用强制转换是有意义的。 但是我一直无法使它发挥作用。

我有一个InkPoint类,它有一个Point对象和一些其他成员。 我想调用DrawLines(Pen, Point[])函数。 但是,我有一个InkPoint[]数组。

这是我的class级和我目前必须使用的代码,它会复制:

 public class InkPoint { public InkPoint(int x, int y) { point = new Point(x, y); } public Point point { get; set; } public static implicit operator Point(InkPoint p) { return p.point; } } private void Form1_Paint(object sender, PaintEventArgs e) { InkPoint[] inkPoints = { new InkPoint(1,2), new InkPoint(3,4) }; Point[] points = Array.ConvertAll(inkPoints, x => x.point); Pen pen = new Pen(Color.Black, 1); e.Graphics.DrawLines(pen, points); } 

我宁愿调用它,但它不会编译,引用无效的参数:

 e.Graphics.DrawLines(pen, inkPoints.Cast()); // Compile err: invalid args 

我也试过迭代一个演员,但它抛出exception,引用演员无效

 foreach (Point p in inkPoints.Cast()) { } // Exception: cast not valid 

我不明白为什么specified cast is not valid因为我已经定义了一个隐式运算符。 我能够做到以下几点:

 InkPoint ip = new InkPoint(10, 20); Point p1 = ip; // implicit conversion Point p2 = (Point)ip; // cast 

对我来说,情况实际上比这复杂一点。 我实际上有一个InkPoints ListList ,但DrawLines函数只接受数组。 所以我的代码看起来像这样:

 List inkPoints = new List(); inkPoints.Add(new InkPoint(5, 10)); inkPoints.Add(new InkPoint(10, 15)); Point[] points = inkPoints.ConvertAll(x => x.point).ToArray(); 

我可以稍微重新安排它:

 Point[] points = Array.ConvertAll(inkPoints.ToArray(), x => x.point); 

所以我认为这里实际上有两个副本。 这很烦人,因为我想做的就是绘制线条。 DrawLines函数应该能够迭代一些包含对可以隐式转换为Point对象的对象的引用的数组/列表,这似乎是不合理的。

想象一下,如果Arrays使用与.Net中其他集合相同的语法,那么您要比较的是带有ArrayArray 。 您不会将ListList 。 嗯,这基本上就是你想要的。

我建议使用一个简单的扩展方法来获得你想要的结果,你需要稍微改变你的语法来说’B [] arrB = arrA.ToBArray();`

 static class ArrayCast { public static B[] ToBArray(this A[] source) { var result = new B[source.Length]; for (int i = 0;i < source.Length;i++) result[i] = source[i]; return result; } }