Domanda

Sento che la mia domanda è piuttosto stupida, o un altro modo per dirla è: sono troppo perso nel mio codice per vedere una soluzione per ora. Rimani troppo a lungo su un problema e la tua visione diventa sempre più stretta & Gt; & Lt ;. Inoltre non sono abbastanza bravo con l'eredità, il polimorfismo e così via

Ecco l'idea: ho un elenco multiplo di classe derivata e vorrei chiamare funzioni generiche su quegli elenchi (accesso e modifica dei membri della classe base). Sento che c'è qualcosa a che fare con l'eredità, ma non riesco a farlo funzionare come voglio per ora.

Ecco un esempio molto semplice di ciò che intendo fare:

class Baseclass
{
    public int ID;
    public string Name;
}
class DerivedClass1 : Baseclass
{
}

private void FuncOnBase(List<Baseclass> _collection)
{
    // ...

    foreach (Baseclass obj in _collection)
    {
        ++obj.ID;
    }

    // ...
}
private void FuncTest()
{
    List<DerivedClass1> collection1 = new List<DerivedClass1>();
    collection1.Add(new DerivedClass1() { ID = 1 });
    collection1.Add(new DerivedClass1() { ID = 2 });
    collection1.Add(new DerivedClass1() { ID = 3 });

    FuncOnBase(collection1);   //  ==> forbidden, cannot convert the derived class list to the base class list
}
È stato utile?

Soluzione

Devo amare la varianza. Un List<DerivedClass1> non è non un List<Baseclass> - altrimenti, FuncOnBase potrebbe tentare di aggiungere un Baseclass all'elenco e il compilatore non lo individuerebbe.

Un trucco è usare un metodo generico:

private void FuncOnBase<T>(List<T> _collection) where T : Baseclass
{
    // ...

    foreach (T obj in _collection)
    {
        obj.ID++;
    }

    // ...
}

In termini dell'esempio che ho presentato sopra, nota che siamo in grado di aggiungere un T all'elenco; utile in particolare se aggiungiamo il T : new() vincolo o passiamo (ad esempio) a params T[].

Nota anche che IEnumerable<T> diventa covariante in C # 4.0 / .NET 4.0, quindi se passi solo un IEnumerable<Baseclass> (piuttosto che un elenco) funzionerebbe " come " :

private void FuncOnBase(IEnumerable<Baseclass> _collection)
{
   ///...
}

Altri suggerimenti

Se stai solo eseguendo un foreach, dichiara FuncOnBase(IEnumerable<Baseclass> collection), che puoi chiamare da FuncTest in questo modo:

FuncOnBase(collection1.Cast<Baseclass>());

Quando dichiari un metodo con un parametro List<T> ma usi solo le sue IEnumerable<T> caratteristiche, stai aggiungendo vincoli API che non significano nulla nel tuo codice.

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