Ist es falsch, einen Enumerator eines Kindes Klasse einen Enumerator von einer übergeordneten Klasse zu werfen?

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

  •  04-07-2019
  •  | 
  •  

Frage

Ich habe einen Fehler in meinem Build bekam die sagt:

  

Fehler 12 kann nicht implizit konvertieren   Art   'System.Collections.Generic.IEnumerator '   zu   'System.Collections.Generic.IEnumerator '.   Eine explizite Konvertierung vorhanden ist (sind Sie   fehlt ein gegossenes?)

Ist es falsch, sie einfach wegzuwerfen?

Dies ist mein Code:

public Dictionary<Int32, BaseClass> Map { get; private set; }

public IEnumerator<BaseClass> GetEnumerator()
        {
            return this.Map.Values.GetEnumerator();
        }

public IEnumerator<IParentClass> IEnumerable<IParentClass>.GetEnumerator()
        {
            return this.GetEnumerator(); // ERROR!
        }

Meine Frage ist, kann ich nur diese Zeile ändern:

return this.GetEnumerator();

zu:

return (IEnumerator<IParentClass>)this.GetEnumerator();

(ohne schlechte Nebenwirkungen)?

akzeptierte Antwort:
Ich habe die Funktion in dem folgenden geändert (nach Jon Skeet Beitrag lesen):

IEnumerator<IParentClass> IEnumerable<IParentClass>.GetEnumerator()
        {
            return this.Map.Values.Cast<IParentClass>().GetEnumerator();
        }
War es hilfreich?

Lösung

Nein, Sie können nicht, weil Generika kovariant sind nicht in C # im Moment. .NET selbst hat eine gewisse Unterstützung (für die Delegierten und Schnittstellen), aber es ist nicht wirklich verwendet noch.

Wenn Sie IEnumerable<BaseClass> statt IEnumerator<BaseClass> kehren (und unter der Annahme, .Net 3.5) Sie Enumerable.Cast verwenden könnten -. Aber Sie werden zur Zeit benötigen, um Ihre eigene Erweiterungsmethode zu schreiben, z

public static IEnumerator<TParent> Upcast<TParent, TChild>
    (this IEnumerator<TChild> source)
    where TChild : TParent
{
    while (source.MoveNext())
    {
        yield return source.Current;
    }
}

Als Alternative in Ihrem Fall könnten Sie früher CAST:

return this.Map.Values.Cast<BaseClass>().GetEnumerator();

Andere Tipps

Nein, Sie können nicht, zumindest in C # 3.0 und unter Schnittstelle Varianz wird nicht unterstützt. Siehe Eric Lippert ausgezeichnete Serie auf diesem und insbesondere dieses .

Nein, es ist nicht sicher, siehe unten:

System.Collections.Generic verwendet wird; class Foo {} Klasse Bar: Foo {}

static class Program
{
    static IEnumerator<Foo> GetBase() {
        yield return new Foo();
        yield return new Bar();
    }
    static IEnumerator<Bar> GetDerived()
    {
        return (IEnumerator<Bar>)GetBase();
    }
    static void Main()
    {
        var obj = GetDerived(); // EXCEPTION
    }
}

Allerdings sollten Sie in der Lage sein, einen Iteratorblock zu verwenden, um die Besetzung für Sie zu tun?

static IEnumerator<Bar> GetDerived()
{
    using (IEnumerator<Foo> e = GetBase())
    {
        while (e.MoveNext())
        {
            // or use "as" and only return valid data
            yield return (Bar)e.Current;
        }
    }
}

Um die Vernunft Warum diese nicht geeignet ist, die anstelle eines Enumerator, ein List. Beide verwenden Generika - der Compiler entweder eine in besonderer Weise in Bezug auf generische Argumente nicht behandeln

.
void doStuff() {
    List<IParentThing> list = getList();
    list.add(new ChildThing2());
}

List<IParentThing> getList() {
    return new List<ChildThing1>();  //ERROR!
}

Dieses erste Verfahren ist in Ordnung - eine Liste der IParentThings Lage sein sollte, eine ChildThing2 zu empfangen. in anderen Worten, wenn der ChildThing1 erlaubt wurde als ChildThing2 zu werfen, wäre es in der Lage sein mit alle IParentThings kann keine ChildThing1, oder in der Tat jeden Implementierer von List&lt;ChildThing1> andere als List&lt;IParent> Griff em> Subklassen von IParentThing, nicht nur IParentThing und ChildThing1.

Beachten Sie, dass Java Generics eine Möglichkeit haben, zu sagen, dass „ich eine Liste von etwas wollen, das von dieser erbt“ neben „Ich möchte eine Liste von allem, was diese erbt“, die für interessanter (und meiner Meinung nach erlaubt elegant) Lösungen für einige Probleme.

IEnumerator<BaseClass> und IEnumerator<ParentClass> sind nicht verwandt, obwohl ihre generischen Parameter sind. Ich würde stattdessen eine LINQ Select Erweiterung Methode, wie so verwenden:

return this.Select(x => (IParentClass)x).GetEnumerator();

oder die Cast Erweiterungsmethode:

return this.Cast<IParentClass>().GetEnumerator();
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top