Come delegare l'implementazione dell'interfaccia ad un'altra classe in C #

StackOverflow https://stackoverflow.com/questions/126164

  •  02-07-2019
  •  | 
  •  

Domanda

Assumi la seguente classe:

public class MyEnum: IEnumerator
{
    private List<SomeObject> _myList = new List<SomeObject>();
...
}

È necessario implementare i metodi IEnumerator in MyEnum. Ma è possibile "delegare" o reindirizzare l'implementazione per IEnumerator direttamente su _myList senza la necessità di implementare i metodi IEnumerator?

È stato utile?

Soluzione

Metodo 1: Continuare a utilizzare l'incapsulamento e inoltrare le chiamate all'implementazione dell'elenco.

class SomeObject
{
}

class MyEnum : IEnumerable<SomeObject>
{
    private List<SomeObject> _myList = new List<SomeObject>();

    public void Add(SomeObject o)
    {
        _myList.Add(o);
    }

    public IEnumerator<SomeObject> GetEnumerator()
    {
        return _myList.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }
}

class Program
{
    static void Main(string[] args)
    {
        MyEnum a = new MyEnum();
        a.Add(new SomeObject());

        foreach (SomeObject o in a)
        {
            Console.WriteLine(o.GetType().ToString());
        }

        Console.ReadLine();
    }
}

Metodo 2: Eredita dall'implementazione dell'elenco, ottieni questo comportamento gratuitamente.

class SomeObject
{
}

class MyEnum : List<SomeObject>
{
}

class Program
{
    static void Main(string[] args)
    {
        MyEnum a = new MyEnum();
        a.Add(new SomeObject());

        foreach (SomeObject o in a)
        {
            Console.WriteLine(o.GetType().ToString());
        }

        Console.ReadLine();
    }
}

Metodo 1 consente un sandboxing migliore in quanto non esiste alcun metodo che verrà chiamato in Elenco senza la conoscenza di MyEnum. Per il minimo sforzo è preferibile Metodo 2 .

Altri suggerimenti

Puoi farlo:

public class MyEnum : IEnumerator {
    private List<SomeObject> _myList = new List<SomeObject>();
    public IEnumerator GetEnumerator() { return this._myList.GetEnumerator(); }
}

Il motivo è semplice. La tua classe può contenere diversi campi che sono raccolte, quindi compilatore / ambiente non può sapere quale campo deve essere utilizzato per implementare & Quot; IEnumerator & Quot ;.

EIDT: Sono d'accordo con @pb - dovresti implementare IEnumerator < SomeObject > interfaccia.

A parte l'utilizzo del metodo pb, questo non è possibile per un & # 8220; semplice & # 8221; motivo: il primo argomento deve passare un puntatore this al metodo dell'interfaccia. Quando chiami GetEnumerator sul tuo oggetto, questo puntatore sarà il tuo oggetto. Tuttavia, affinché l'invocazione funzioni nell'elenco nidificato, il puntatore dovrebbe essere un riferimento a tale elenco, non alla tua classe.

Pertanto è necessario delegare esplicitamente il metodo all'altro oggetto.

(E comunque, il consiglio nell'altra risposta era giusto: usa IEnumerator<T>, non IEnumerable!)

Se si desidera restituire una raccolta in un modo in cui il chiamante non è in grado di modificare la raccolta, è possibile che si desideri avvolgere l'elenco in un oggetto ReadOnlyCollection < > e restituisce IEnumerable < > di ReadOnlyCollection < > ;.

In questo modo puoi essere sicuro che la tua collezione non verrà modificata.

A meno che tu non derivi dalla Lista < T > ;.

public class MyEnum : List<SomeObject>, IEnumerable<SomeObject>{}

Grazie a tutti per il contributo e le spiegazioni. Alla fine ho combinato alcune delle tue risposte a quanto segue:

    class MyEnum : IEnumerable<SomeObject>
{
    private List<SomeObject> _myList = new List<SomeObject>();
    public IEnumerator<SomeObject> GetEnumerator()
    {
        // Create a read-only copy of the list.
        ReadOnlyCollection<CustomDevice> items = new ReadOnlyCollection<CustomDevice>(_myList);
        return items.GetEnumerator();
    }
}

Questa soluzione è garantire che il codice chiamante non sia in grado di modificare l'elenco e che ogni enumeratore sia indipendente dagli altri in ogni modo (ad es. con l'ordinamento). Grazie ancora.

Nota che grazie a duck-typing , puoi utilizzare foreach su qualsiasi oggetto che abbia un metodo GetEnumerator - il tipo di oggetto non deve effettivamente implementare IEnumerable.

Quindi, se lo fai:

class SomeObject
{
}

 class MyEnum
 {
    private List<SomeObject> _myList = new List<SomeObject>();

    public IEnumerator<SomeObject> GetEnumerator()
    {
        return _myList.GetEnumerator();
    }
 }

Quindi funziona perfettamente:

MyEnum objects = new MyEnum();
// ... add some objects
foreach (SomeObject obj in objects)
{
    Console.WriteLine(obj.ToString());
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top