| 

.NET C# Java Javascript Exception

2
Hallo Zusammen, habe ein Verständnis Problem.

Ich möchte gerne eine Liste von einem Type als Listenkopie nach außen geben. Dafür soll eine Generics Methode verwendet werden. Leider funktioniert dies so nicht. (Im Beispiel wird die Liste in der Funktion erzeugt, eigentlich kommt diese von einem Klassen-Member.)

public interface InterfaceOfAType { }
public class AType : InterfaceOfAType { }
public InterfaceOfAType getInstanceOfAType()
{ return new AType(); }
public List<T> genericFunction<T>() where T : InterfaceOfAType
{
List<InterfaceOfAType> instance = new List<InterfaceOfAType>();
instance.Add(getInstanceOfAType());
instance.Add(getInstanceOfAType());
instance.Add(getInstanceOfAType());

// return a listcopy of instance
List<T> t = new List<T>();
t.AddRange(instance); // !! Fehler
return t;
}


Die Letzte Zeile wird vom Compiler angezettelt.
Die beste Übereinstimmung für die überladene List<T>.AddRange(IEnumerable<T>)-Methode hat einige ungültige Argumente.


Ich gehe eigentlich davon aus dass die neue Liste vom Typ T identisch mit der bereits erstellten ist.

Warum ist dies dennoch nicht so? und wie kann man das besser lösen?

Vielen Dank.
05.04.2011
smartic 510 1 8
Floyd 14,6k 3 9
Edit: C#-Tagg hinzugefügt
Floyd 05.04.2011
3 Antworten
3
Wie Matthias bereits schrieb, solltest du erklären, warum du generics verwenden möchtest und dein Code nicht einfach wie unten aussieht. Dann können wir dir besser helfen.

public List<InterfaceOfAType> NonGenericFunction() 
{
List<InterfaceOfAType> instance = new List<InterfaceOfAType>();
instance.Add(getInstanceOfAType());
instance.Add(getInstanceOfAType());
instance.Add(getInstanceOfAType());

// return a listcopy of instance
List<InterfaceOfAType> t = new List<InterfaceOfAType>();

t.AddRange(instance);// !! kein Fehler mehr
return t;
}


Ergänzung nach Kommentar:

Meinst du so etwas oder verstehe ich das Problem falsch?

public interface InterfaceOfAType { void Foo();}
public interface ExtendedInterfaceOfAType : InterfaceOfAType { void Foo2(); }
public class AType : ExtendedInterfaceOfAType
{
public void Foo() { }
public void Foo2() { }
}
public ExtendedInterfaceOfAType getInstanceOfAType()
{ return new AType(); }

public List<InterfaceOfAType> NonGenericFunction()
{
List<InterfaceOfAType> instance = new List<InterfaceOfAType>();
instance.Add(getInstanceOfAType());
instance.Add(getInstanceOfAType());
instance.Add(getInstanceOfAType());

// return a listcopy of instance
List<InterfaceOfAType> t = new List<InterfaceOfAType>();

t.AddRange(instance);// !! kein Fehler mehr
return t;
}



Der zugehörige Aufrufe könnte wie folgt aussehen:
foreach (ExtendedInterfaceOfAType interfaceOfAType in NonGenericFunction())
{
interfaceOfAType.Foo();
interfaceOfAType.Foo2();
}
05.04.2011
Jürgen Luhr 7,1k 1 9
Grund ist, das InterfaceOfAType nur eine Basis Interface sein soll, und ein interface ExtendedInterfaceOfAType ebenfalls bearbeitet werden sollte. Ich glaube ich erhoffe mir zu viel von Generics. :-)
smartic 05.04.2011
Dein Code erzeugt eine Liste von AType-Instanzen. AType implementiert nicht ExtendedInterfaceOfAType, oder? Und auch allgemein gilt: nicht jede Instanz von InterfaceOfAType ist auch eine Instanz von ExtendedInterfaceOfAType. genericFunction<ExtendedInterfaceOfAType> müßte aber genau das liefern: eine Liste von Instanzen einer Klasse, die ExtendedInterfaceOfAType implementiert. Die muss irgendwo herkommen, und das "woher" ist die Frage, die Du beantworten musst. Wenn das geklärt ist, könntest Du z.B. getInstanceOfAType umbauen zu getInstance<T> - und dann passt das auch wieder zusammen.
Matthias Hlawatsch 05.04.2011
So, nun denke ich mal dass was ich vorhatte so nicht gehen kann, obwohl die erste Implementierung funktioniert, aber in Blick auf die Erweiterung fehl schlagen muss. Ich werde wohl das Konzept mit der NonGenericFunction umsetzen, da dies plausibel klingt. Danke für den Hinweis.
smartic 05.04.2011
1
AddRange erwartet ein IEnumerable<T>. T ist hier ein beliebiger Typ, mit der Einschränkung, dass er InterfaceOfAType implementiert. Es könnte z.B. AType sein - das entscheidet sich erst beim Aufruf. instance hingegen ist vom Typ List<InterfaceOfAType> und damit auch IEnumerable<InterfaceOfAType>. Generische Typen lassen sich aber nicht ineinander casten (ab .NET 4.0 gibt es da Ausnahmen, aber ich glaube, die greifen hier nicht). Wenn der Cast von IEnumerable<InterfaceOfAType> auf IEnumerable<T> funktionieren soll, müßte sich insbesondere auch IEnumerable<InterfaceOfAType> nach IEnumerable<AType> casten lassen (denn beim Aufruf von genericFunction könntest Du ja zum Beispiel T auf AType festlegen). Das geht aber nicht.

Eine naheliegende Lösung wäre, auf die generische Methode zu verzichten und stattdessen List<InterfaceOfAType> zurückzugeben. Vermutlich hast Du aber einen Grund, warum Du einerseits AType hinter dem Interface verstecken, andererseits aber mit einer generischen Methode arbeiten willst. Den müßtest Du mal noch erklären - an dem Punkt verstehe ich leider nicht, was Du bezweckst.

Bedenke, dass genericFunction, so wie Du es deklarierst, ja auch noch funktionieren muss, wenn jemand
class OtherType : InterfaceOfAType
einführt und dann genericFunction<OtherType>() aufruft. Eine List<OtherType> kannst Du mit den Elementen von instance aber nicht herbeizaubern, denn da stecken AType-Instanzen drin, und die haben mit OtherType nichts zu tun.
05.04.2011
Matthias Hlawatsch 13,2k 4 9
0
Probier es mal mit einem Cast:

// return a listcopy of instance
List<T> t = new List<T>();
t.AddRange(instance.Cast<T>());
return t;
05.04.2011
Floyd 14,6k 3 9
-1: Das kompiliert, liefert aber u.U. zur Laufzeit eine InvalidCastException - nämlich dann, wenn irgendjemand class OtherType : InterfaceOfAType einführt und dann jemand genericFunction<OtherType> aufruft.
Matthias Hlawatsch 05.04.2011
gilt dies auch für eine Konvertierung wie?
List<T> ts = new List<T>();
foreach (T t in instance)
ts.Add((T)t);
Ich verwende mom. noch .net.2.0
smartic 05.04.2011
@smartic: warum die foreach-Zeile überhaupt kompiliert, verstehe ich ehrlich gesagt gerade nicht. In instance ist nicht "T", sondern (irgendein) InterfaceOfAType. - Ansonsten läuft es aber trotzdem darauf hinaus, AType in OtherType zu casten, und das wird nicht gehen.
Matthias Hlawatsch 05.04.2011
mhh, eigentlich enthält die Liste nur das Interface vom Typ InterfaceOfAType, also "Cast"e/stecke ich nur das Interface von AType in die liste. Den Generic grenze ich ja ein, indem ich sage das er nur von einem bestimmten Interface sein darf. Wenn ich die Listen-Members verwende, verwende ich ebenso auch nur das Interface. Ein Objekt-Type-Cast findet nach meinem Verständnis nicht statt.
smartic 05.04.2011
Du grenzt den Typparameter dahingehend ein, dass nur Typen erlaubt sind, die das Interface implementieren. D.h. man darf genericFunction für jedes T aufrufen, das das Interface implementiert, und dann erwarten, dass eine Liste von Ts zurückkommt - und nicht eine Liste von Instanzen irgendeines (anderen) Typs, der auch das Interface implementiert - in Deinem Fall AType. Durchdenke Dir nochmal den Fall mit OtherType: genericFunction<OtherType> muss eine List<OtherType> zurückgeben, aber instance enthält nichts vom Typ OtherType.
Matthias Hlawatsch 05.04.2011

Stelle deine .net-Frage jetzt!
TOP TECHNOLOGIES CONSULTING GmbH