Domanda

Ho il seguente codice

class Program
    {
        static void Main(string[] args)
        {
            List<A> aList = new List<A>();

            var aObj = new A();

            aObj.Go(aList.Cast<IB>());
        }
    }

    class A : IB
    {
        public void Go(IEnumerable<IB> interfaceList)
        {
            foreach (IB ibby in interfaceList)
            {
                Console.WriteLine("Here");
            }
        }
    }

    interface IB
    {
        void Go(IEnumerable<IB> interfaceList);
    }

}

Inizialmente ho provato a passare un elenco ma che non funziona . Dopo tanto aiuto da SO ho scoperto che passare IEnumerable è il l'unico modo per far passare gli oggetti come .ofType (IB).

Sfortunatamente per me, nel mio codice la seguente riga verrà eseguita migliaia di volte:

aList.Cast<IB>();

Mi chiedevo se qualcuno sapesse come è stato implementato algoritmicamente (in IL) e quale sia il suo ordine temporale.

Vale a dire, è più veloce di un ciclo foreach che lancia semplicemente ogni elemento o è esattamente quello che fa?

MODIFICA La classe principale deve mantenere un elenco degli oggetti reali. Ma al lettore è consentito toccarli solo attraverso l'interfaccia.

È stato utile?

Soluzione

Dovresti cambiare Vai in:

public void Go<T>(IEnumerable<T> interfaceList)
    where T : IB
{
    foreach (IB ibby in interfaceList)
    {
        Console.WriteLine("Here");
    }
}

Allora starai bene senza bisogno di chiamare Cast . Sospetto che l'implementazione del codice sorgente di Cast sia piuttosto semplice, anche se credo che sia cambiata tra 3.5 e 3.5SP1. Tuttavia, probabilmente deve installare una nuova macchina a stati ecc. Nel normale modo di blocco iteratore. Meglio evitarlo se possibile.

Anche se il nuovo metodo è generico, l'inferenza del tipo dovrebbe in genere occuparsene, quindi non è necessario specificare T esplicitamente.

Altri suggerimenti

Perché non dichiarare semplicemente la lista come:

List<IB> aList = new List<IB>();

C'è qualcosa in particolare che richiede di avere un elenco delle classi concrete?


Quindi in quel caso renderei la lista parte del dominio. Avere un'interfaccia come IIBCollection (ad esempio), esporre i metodi su cui si desidera che il lettore possa accedere. Ad esempio:

interface IIBCollection{
    IEnumerable<IB> IBs { get; }
}

// and in your implementation you can do

IEnumerable<IB> IBs { 
    get { 
        foreach(IB ib in innerList) yield return ib; 
}}

È implementato internamente come CastIterator che è leggermente più lento di una foreach che lancia ogni oggetto.

Il metodo Cast semplicemente scorrerà l'elenco e lancerà ogni elemento.

Se hai intenzione di utilizzare l'elenco migliaia di volte, archivia semplicemente il risultato del casting come elenco.

Se ciò non è possibile (ovvero si modifica l'elenco ogni volta), considerare di lavorare con un Elenco < IB > invece di un Elenco < A > .

Non è a questo che serve la covarianza in C #? Non vedo cosa stai cercando di fare, quindi non posso commentare il motivo per cui è stato espulso migliaia e migliaia di volte.

Sarebbe una questione abbastanza semplice solo confrontare i due metodi (metodo di estensione Cast e un ciclo for con un cast). Ma dato che Cast è un metodo di estensione della classe Enumerable e si occupa genericamente di IEnumerables, immagino che questa sia precisamente la sua implementazione. Se vuoi la massima velocità, potrebbe essere meglio implementare il tuo metodo di estensione che funziona specificamente su List (ottiene ogni elemento dal suo indice), che dovrebbe essere leggermente più veloce dato il sovraccarico degli iteratori. Tuttavia, entrambi i metodi dovrebbero richiedere O (n) tempo, quindi la differenza non dovrebbe essere enorme. È qualcosa che vale la pena confrontare, tuttavia ...

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top