Pregunta

Tengo las siguientes clases con un operador de conversión implícita definida:

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

Ahora, yo puedo implícitamente fundido de A a B.

Pero por qué no puedo implícitamente fundido 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;
}

Gracias, Malki.

¿Fue útil?

Solución

Como se ha mencionado Mehrdad Afshari, estás fuera de suerte haciendo esto de manera implícita. Usted tendrá que obtener explícito, y va a implicar una copia matriz. Afortunadamente, es probable que pueda hacerlo con una sola línea:

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

Aunque si sólo desea arrB iterate en un comunicado foreach, puede evitar la copia omitiendo ToArray()

Otros consejos

covarianza de matriz sólo funciona para los tipos de referencia y en la jerarquía de herencia (nota que no es una representación de cambio de conversión:. Sólo un conjunto de punteros con tamaño idéntico interpretan de manera diferente) no funcionará para los tipos de valor y conversiones definidas por el usuario.

ConvertAll

Sólo para ser explícita, aquí es cómo se utiliza ConvertAll.

En el caso de que class B tiene un miembro de class A llamada m_a, hacer esto:

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

.

Si class B tiene algunos datos de los miembros que se necesita para manipular antes de poder devolver un objeto de tipo A (tales como convertir un montón de valores numéricos en una cadena de descripción), haga lo siguiente:

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

.

También puede utilizar las funciones 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;
    }));

.

Sería bueno si ConvertAll podría utilizar el operador implícito para hacer la conversión, pero no he encontrado la manera de hacer eso.

.

Reparto

@Randolpho @bottlenecked

En los casos en los que lo único que desea iterar y prefiere no hacer una copia, el uso de yeso tiene sentido. Sin embargo, he sido capaz de hacer que funcione.

Tengo una clase InkPoint que tiene un objeto Point y algunos otros miembros. Quiero llamar a la función DrawLines(Pen, Point[]). Sin embargo, tengo una matriz de InkPoint[].

Esta es mi clase y el código actualmente tengo que usar, lo que hace una copia:

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

.

Yo prefiero llamar a esta, pero no va a compilar, citando argumentos no válidos:

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

.

También he intentado iteración sobre un molde, pero se produce una excepción, citando el reparto no es válido

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

.

No entiendo por qué el specified cast is not valid ya he definido un operador implícito. Soy capaz de hacer lo siguiente bien:

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

.

Para mí, la situación es en realidad un poco más complicado que eso. De hecho, tengo una lista de InkPoints, List<InkPoint>, pero la función DrawLines sólo acepta matrices. Así que mi apariencia código como este:

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

Me puede reorganizar un poco para esto:

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

.

Así que creo que hay realmente dos copias que suceden aquí. Esto es molesto ya que todo lo que quiero hacer es dibujar las líneas. No parece razonable que la función DrawLines debe ser capaz de iterar sobre alguna matriz / lista que contiene referencias a los objetos que se pueden convertir implícitamente a objetos Point.

Imagine por un momento si matrices utiliza la misma sintaxis que otras colecciones en .Net, y lo que estamos tratando de comparar es un Array<A> con un Array<B>. No compararía un List<A> a un List<B>. Bueno, eso es básicamente lo que estamos tratando.

Me gustaría recomendar el uso de un método simple extensión para obtener el resultado deseado, usted necesita cambiar su sintaxis poco que decir '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;
    }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top