6

我有以下类,其中定义了隐式强制转换运算符:

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;
}

谢谢,马尔基。

4

4 回答 4

9

正如 Mehrdad Afshari 所提到的,你不走运就隐含地这样做了。你必须明确,它会涉及一个数组副本。值得庆幸的是,您可以使用单线来做到这一点:

arrB = arrA.Cast<B>().ToArray();

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

于 2010-06-15T18:06:49.130 回答
5

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

于 2010-06-15T18:03:34.853 回答
2

全部转换

明确地说,这里是您如何使用 ConvertAll。

如果有一个被调用class B的成员,请执行以下操作:class Am_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, A>(B.makeAfromB));

.

您还可以使用 Lambda 函数:

A[] arrA = Array.ConvertAll(arrB, new Converter<B, A>(
    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 @瓶颈

对于您只想迭代并且不想制作副本的情况,使用 cast 是有意义的。但是我一直无法使它工作。

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

这是我的课程和我目前必须使用的代码,它制作了一个副本:

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<Point>()); // Compile err: invalid args

.

我也试过迭代一个演员,但它抛出一个异常,引用演员是无效的

foreach (Point p in inkPoints.Cast<Point>()) { } // 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 列表List<InkPoint>,但该DrawLines函数只接受数组。所以我的代码如下所示:

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

我可以稍微重新安排一下:

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

.

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

于 2012-10-07T03:56:35.320 回答
0

想象一下,如果 Arrays 使用与 .Net 中其他集合相同的语法,而您要比较的是 anArray<A>Array<B>. 您不会将 aList<A>与 a进行比较List<B>。嗯,这基本上就是你正在尝试的。

我建议使用简单的扩展方法来获得你想要的结果,你需要稍微改变你的语法,说 '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;
    }
}
于 2010-06-15T18:22:45.120 回答