Autor Beitrag
shamanu
Hält's aus hier
Beiträge: 10



BeitragVerfasst: Do 06.05.10 19:16 
Ich habe eine abstrakte Basisklasse:
ausblenden C#-Quelltext
1:
public class BasicClass ...					

Und mehrere die davon ableiten:
ausblenden C#-Quelltext
1:
2:
3:
public class ClassA:BasicClass ...
public class ClassB:BasicClass ...
public class ClassC:BasicClass ...

usw.

Diese Klassen werden nun von einer generischen verwendet:
ausblenden C#-Quelltext
1:
public class GenericClass<T> where T:BasicClass					


jetzt erhalte ich die generische Klasse als objekt, würde dies jedoch gerne auf den generischen Typen casten:
ausblenden C#-Quelltext
1:
2:
3:
public void foo(object genericClass){
  GenericClass<BasicClass> gen=genericClass as GenericClass<BasicClass>;
}


Das ganze funktioniert jedoch nicht da das objekt genericClass vom typ GenericClass<ClassA> oder GenericClass<ClassB> usw ist. Ist es möglich das casting auf den generischen basistyp irgendwie durchzuführen?
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Do 06.05.10 19:53 
Wenn die Umwandlung überhaupt sicher ist (wäre sie bei IList<> zum Beispiel nicht), kannst du ab C# 4 ein <out T> setzen (edit: allerdings erst ein Interface extrahieren). Aber ob Kovarianz hier wirklich nötig ist...? Verrate doch mal ein wenig über den konkreten Fall.

_________________
>λ=
Xardas008
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 149

Win 7 Professional x64, Ubuntu 10.04, Windows Server 2008 R2
C#, Visual Studio 2008 Pro, Visual Studio 2010 Ultimate, Eclipse (Java)
BeitragVerfasst: Do 06.05.10 21:56 
Hi,

einen Cast kannst du so ohne weiteres bei Generischen Typen nicht durchführen. Der Grund hierfür ist, das Generics die Vererbungsbeziehung aufheben, diese besteht nur ausserhalb der Generics. Es gibt aber einen Trick den du anwenden kannst. Anbei habe ich (allerdings in Java) einen kleinen Codeausschnitt als Beispiel, den ich eben in Netbeans ausprobiert habe, den solltest du ohne weiteres auf C# übertragen können.

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
ArrayList<Base> b = new ArrayList<Base>();
ArrayList<Derived> d = new ArrayList<Derived>();
Derived d2 = d.get(0); //Wir setzen mal voraus, das bereits ein Element existiert.
b.add(d2);  //Funktioniert
b.add(d);   //Funktioniert nicht --> Compilerfehler


Und zwar ist der Trick, das du dir das zu castende Element aus ClassA nimmst und nach ClassA castest und dieses dann in die BasisClass hinzufügst als neues Element, dies wird dann implizit in den richtigen Typ gecastet.

Gruß
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Do 06.05.10 22:49 
user profile iconXardas008 hat folgendes geschrieben Zum zitierten Posting springen:
einen Cast kannst du so ohne weiteres bei Generischen Typen nicht durchführen.
Na dann lies dir doch bitte mal meinen Beitrag durch. Um noch einen offiziellen Link dazuzupacken: Covariance and Contravariance FAQ

user profile iconXardas008 hat folgendes geschrieben Zum zitierten Posting springen:
Und zwar ist der Trick, das du dir das zu castende Element aus ClassA nimmst und nach ClassA castest und dieses dann in die BasisClass hinzufügst als neues Element, dies wird dann implizit in den richtigen Typ gecastet.
Und wenn es gar nicht um eine Collection geht?

_________________
>λ=
shamanu Threadstarter
Hält's aus hier
Beiträge: 10



BeitragVerfasst: Fr 07.05.10 23:06 
Ok, das casting über ein Interface mit <out T> funktioniert soweit einmal.

Ich muß mir das ganze nochmals genauer anschauen und melde mich dann nochmals.
shamanu Threadstarter
Hält's aus hier
Beiträge: 10



BeitragVerfasst: Do 13.05.10 22:42 
Ich habe die <out T> variante mit Interface nun getestet.
In der Basisversion funktioniert es, jedoch verwende ich in meinen Klassen einen Kontainer welcher einen fehler bezüglich 'T' erzeugt der sagt das der T parameter invariantly sein muß.

ausblenden C#-Quelltext
1:
2:
3:
4:
public interface IElementBase<out T> where T : SingleElementBase
{
   IObservable<KeyValuePair<string, T>> Elements{get; set;}
}


Bezüglich der Frage ob dies wirklich notwendig ist bzw. der konkrete Fall:
Ich habe eine generische Basisklasse "ElementBase". Die konkreten Implementierungen halten dann Sammlungen von zb Audiofiles, Grafiken usw. und werden über einen Contentpresenter dargestellt.
Das hat alles soweit gut funktioniert. Jedoch erweitere ich das ganze nun um eine neue Gui und würde die Objekte gerne als Parameter übergeben ohne für jede Klasse die von ElementBase ableitet eine eigene Methode zu erstellen.
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Do 13.05.10 23:35 
In der Theorie ist an dem Code nichts auszusetzen, praktisch sträubt sich aber eben KeyValuePair dagegen. Da wirst du auf ein eigenes
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
interface ITuple<out T1, out T2>
{
  public T1 Item1 { get; }
  public T2 Item2 { get; }
}
ausweichen müssen.

user profile iconshamanu hat folgendes geschrieben Zum zitierten Posting springen:
Jedoch erweitere ich das ganze nun um eine neue Gui und würde die Objekte gerne als Parameter übergeben ohne für jede Klasse die von ElementBase ableitet eine eigene Methode zu erstellen.
Auf GUI-Ebene (gerade wenn es um WPF geht) ist Typisierung meist nicht mehr wichtig. Wäre es nicht einfacher, eine nicht-generische ElementBase-Basisklasse einzuschieben?

_________________
>λ=
shamanu Threadstarter
Hält's aus hier
Beiträge: 10



BeitragVerfasst: Fr 14.05.10 21:55 
user profile iconKha hat folgendes geschrieben Zum zitierten Posting springen:
Auf GUI-Ebene (gerade wenn es um WPF geht) ist Typisierung meist nicht mehr wichtig. Wäre es nicht einfacher, eine nicht-generische ElementBase-Basisklasse einzuschieben?

Die ElementBase Klasse habe ich eigentlich primär generisch gemacht um einen großen Teil der funktionalität darin implementieren zu können und bei den Elementen die sie hält unabhängig von einem Interface oder ähnlichem zu sein.
Inzwischen scheint mir diese Lösung aber nicht mehr gerade als die Beste. Der Vorschlag mit ITuple funktioniert zwar aber wenn ich noch weiter Funktionalitäten benötige führt dies wohl schnell zu noch mehr Hilfskonstrukten.