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

明確にするために、ConvertAll の使用方法を次に示します。

whereがcalledclass Bのメンバーである場合は、次のようにします。class Am_a

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

.

タイプ A のオブジェクトを返す前に操作する必要があるメンバー データがある場合class B(一連の数値を文字列の説明に変換するなど)、次のようにします。

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 が暗黙の演算子を使用して変換を実行できればいいのですが、その方法がわかりません。

.

キャスト

@ランドルフォ @bottlenecked

単に反復したいだけで、コピーを作成したくない場合は、キャストを使用するのが理にかなっています。しかし、私はそれを機能させることができませんでした。

オブジェクトと他のメンバーを持つ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);

.

つまり、実際にはここで 2 つのコピーが発生していると思います。私がやりたいのは線を描くことだけなので、これは面倒です。DrawLines関数が、暗黙的にオブジェクトに変換できるオブジェクトへの参照を含む配列/リストを反復処理できる必要があることは、不合理ではないようPointです。

于 2012-10-07T03:56:35.320 に答える
0

配列が.Netの他のコレクションと同じ構文を使用していて、比較しようとしているArray<A>のが。である場合を少し想像してみてくださいArray<B>List<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 に答える