C# 中的隐式数组转换

发布于 2024-09-05 09:17:19 字数 510 浏览 10 评论 0原文

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

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

谢谢,马尔基。

I have the following classes with an implicit cast operator defined:

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

Now, I can implicitly cast A to B.

But why can't I implicitly cast A[] to 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;
}

Thanks, Malki.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

夏末 2024-09-12 09:17:19

正如 Mehrdad Afshari 提到的,你隐式地这样做是不走运的。您必须明确说明,并且它将涉及数组副本。值得庆幸的是,您可能可以用一行代码来完成:

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

尽管如果您只想在 foreach 语句中迭代 arrB ,则可以通过省略 来避免复制ToArray()

As Mehrdad Afshari mentioned, you're out of luck doing this implicitly. You'll have to get explicit, and it'll involve an array copy. Thankfully, you can probably do it with a one-liner:

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

Although if you only want to iterate arrB in a foreach statement, you can avoid the copy by omitting ToArray()

南街女流氓 2024-09-12 09:17:19

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

Array covariance only works for reference types and in the inheritance hierarchy (note that it's not a representation-changing conversion: just a set of pointers with identical size interpreted differently.) It will not work for value types and user defined conversions.

筱武穆 2024-09-12 09:17:19

ConvertAll

明确地说,以下是使用 ConvertAll 的方法。

如果 B 类 有一个名为 m_aA 类 成员,请执行以下操作:

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

如果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 可以使用隐式运算符来进行转换,那就太好了,但我还没有弄清楚如何做到这一点。

Cast

@Randolpho @bottlenecked

对于您只想迭代并且不想制作副本的情况,使用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

我不明白为什么指定的转换无效,因为我定义了一个隐式运算符。我能够很好地执行以下操作:

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

对我来说,情况实际上比这稍微复杂一些。我实际上有一个 InkPoints 列表,List,但 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 对象的对象引用的数组/列表,这似乎并非不合理。

ConvertAll

Just to be explicit, here is how you use ConvertAll.

In the case where class B has a member of class A called m_a, do this:

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

.

If class B has some member data that you need to manipulate before you can return an object of type A (such as turning a bunch of numerical values into a string description), do this:

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

.

You can also use Lambda functions:

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

.

It would be nice if ConvertAll could use the implicit operator to do the conversion, but I haven't figured out how to do that.

.

Cast

@Randolpho @bottlenecked

For the cases where you simply want to iterate and would prefer not to make a copy, using cast makes sense. However I have been unable to make it work.

I have an InkPoint class which has a Point object and some other members. I want to call the DrawLines(Pen, Point[]) function. However, I have an array of InkPoint[].

Here is my class and the code I currently have to use, which makes a copy:

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

.

I would rather call this, but it won't compile, citing invalid arguments:

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

.

I've also tried iterating over a cast, but it throws an exception, citing the cast is not valid

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

.

I don't understand why the specified cast is not valid since I've defined an implicit operator. I'm able to do the following just fine:

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

.

For me, the situation is actually slightly more complicated than that. I actually have a list of InkPoints, List<InkPoint>, but the DrawLines function accepts only arrays. So my code looks like this:

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();

I can rearrange it slightly to this:

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

.

So I think there's actually two copies happening here. This is annoying since all I want to do is draw the lines. It doesn't seem unreasonable that the DrawLines function should be able to iterate over some array/list that contains references to objects that can be implicitly converted to Point objects.

日裸衫吸 2024-09-12 09:17:19

想象一下,如果数组使用与 .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;
    }
}

Imagine for a moment if Arrays used the same syntax as other collections in .Net, and what you're trying to compare is an Array<A> with an Array<B>. You wouldn't compare a List<A> to a List<B>. Well, that's essentially what you're trying.

I'd recommend using a simple extension method to get the result you want, you'll need to change your syntax slightly to say '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;
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文