Pergunta

Eu tenho as seguintes aulas com um operador de elenco implícito definido:

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

Agora, posso lançar implicitamente a B.

Mas por que não posso implicitamente lançar um [] para 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;
}

Obrigado, Malki.

Foi útil?

Solução

Como Mehrdad Afshari mencionou, você está sem sorte fazendo isso implicitamente. Você terá que ficar explícito e isso envolverá uma cópia da matriz. Felizmente, você provavelmente pode fazer isso com uma linha:

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

Embora se você quiser apenas iterar arrB em um foreach declaração, você pode evitar a cópia omitindo ToArray()

Outras dicas

A covariância da matriz funciona apenas para tipos de referência e na hierarquia da herança (observe que não é uma conversão que muda a representação: apenas um conjunto de ponteiros com tamanho idêntico interpretados de maneira diferente.) Não funcionará para tipos de valor e conversões definidas pelo usuário.

Converter tudo

Só para ser explícito, eis como você usa o Convertall.

No caso onde class B tem um membro de class A chamado m_a, fazem isto:

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

.

Se class B Tem alguns dados de membros que você precisa manipular antes de retornar um objeto do tipo A (como transformar vários valores numéricos em uma descrição da string), faça isso:

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

.

Você também pode usar funções 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;
    }));

.

Seria bom se a Convertall pudesse usar o operador implícito para fazer a conversão, mas não descobri como fazer isso.

.

Elenco

@Randolpho @bottlenecked

Para os casos em que você simplesmente deseja iterar e prefere não fazer uma cópia, o uso do elenco faz sentido. No entanto, não consegui fazê -lo funcionar.

eu tenho um InkPoint classe que tem um Point objeto e alguns outros membros. Eu quero ligar para o DrawLines(Pen, Point[]) função. No entanto, eu tenho uma variedade de InkPoint[].

Aqui está minha aula e o código que atualmente preciso usar, o que faz uma cópia:

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

.

Prefiro chamar isso, mas não vai compilar, citando argumentos inválidos:

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

.

Eu também tentei iterar um elenco, mas ele joga uma exceção, citando o elenco não é válido

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

.

Eu não entendo por que o specified cast is not valid Desde que eu defini um operador implícito. Eu sou capaz de fazer o seguinte bem:

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

.

Para mim, a situação é realmente um pouco mais complicada do que isso. Na verdade, eu tenho uma lista de tintas, List<InkPoint>, mas o DrawLines Função aceita apenas matrizes. Então, meu código se parece com o seguinte:

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

Eu posso reorganizá -lo um pouco para isso:

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

.

Então eu acho que há realmente duas cópias acontecendo aqui. Isso é irritante, pois tudo o que quero fazer é desenhar as linhas. Não parece irracional que o DrawLines A função deve ser capaz de iterar sobre alguma matriz/lista que contém referências a objetos que podem ser implicitamente convertidos para Point objetos.

Imagine por um momento se as matrizes usavam a mesma sintaxe que outras coleções no .NET, e o que você está tentando comparar é um Array<A> com um Array<B>. Você não compararia um List<A> para um List<B>. Bem, isso é essencialmente o que você está tentando.

Eu recomendo usar um método de extensão simples para obter o resultado que você deseja, você precisará alterar sua sintaxe um pouco para dizer '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 em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top