Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

Implizierter Cast bei Listen (und anderen Datenstrukturen) nicht möglich? [==> Kovarianz-Problem]
Briefkasten
myCSharp.de - Member

Avatar #avatar-1523.gif


Dabei seit:
Beiträge: 444

Themenstarter:

Implizierter Cast bei Listen (und anderen Datenstrukturen) nicht möglich? [==> Kovarianz-Problem]

beantworten | zitieren | melden

Hallo,

ich bin anscheinend in C# ein bisschen eingerostet was Generizitäten und Casts betrifft.

Für meine Klasse:

    public class Vertex<W,D> : IVertex<W,D>
        where W : IComparable<W>
    {

habe ich eine Extension geschrieben:

public static IEnumerable<IVertex<W, D>> Depth_First_Traversal<W, D>(this IVertex<W, D> s, IList<IVertex<W, D>> visited)
            where W : IComparable<W>
        {

Nun möchte ich diese Extension aufrufen was mir nur mit der Angabe vom Typ IVertex gelingt:


            Vertex<int, object> v1 = new Vertex<int, object>();
            v1.Depth_First_Traversal<int, object>(new List<IVertex<int, object>>());

Aber eigentlich sollte das doch auch so gehen:

            Vertex<int, object> v1 = new Vertex<int, object>();
            v1.Depth_First_Traversal<int, object>(new List<Vertex<int, object>>());
was aber in einem Fehler resultiert:
Fehler
Error 3 Argument 2: cannot convert from 'System.Collections.Generic.List<Get.DataStructure.Vertex<int,object>>' to 'System.Collections.Generic.IList<Get.DataStructure.IVertex<int,object>>'
Ich kann beim Parameter "IList visited" auch eine Liste übergeben (welche ja das Interface implementiert). Geht mein vorhaben bei Listen nicht? Falls ja, gibt es dafür ein Workaround?
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von Briefkasten am .
Schaut mal im IRC vorbei:
Server: [email protected]#c#.de oder [email protected]#csharp
private Nachricht | Beiträge des Benutzers
Palladin007
myCSharp.de - Member

Avatar #avatar-4140.png


Dabei seit:
Beiträge: 1516
Herkunft: Düsseldorf

beantworten | zitieren | melden

Das was du haben willst, geht nur, wenn der generische Typ-Parameter mit einem out versehen ist.

Das würde den generischen Typ-Parameter als kovariant kennzeichnen, was bei IList allerdings nicht der Fall ist.

Einen Workaround gibt es meines Wissens nach nicht.
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von Palladin007 am .
private Nachricht | Beiträge des Benutzers
Briefkasten
myCSharp.de - Member

Avatar #avatar-1523.gif


Dabei seit:
Beiträge: 444

Themenstarter:

beantworten | zitieren | melden

Danke, das hat mir schon weitergeholfen.
Schaut mal im IRC vorbei:
Server: [email protected]#c#.de oder [email protected]#csharp
private Nachricht | Beiträge des Benutzers
Briefkasten
myCSharp.de - Member

Avatar #avatar-1523.gif


Dabei seit:
Beiträge: 444

Themenstarter:

beantworten | zitieren | melden

Moderationshinweis von herbivore (07.03.2014 - 07:44:08):

Beitrag von Datenstruktur flexibel gestalten hierher verschoben, da es weiterhin um das Kovarianz-Problem geht ==> Text entsprechend angepasst.


Aufgrund des obigen Beitrags von Palladin007 habe ich das Gefühl, dass mein Ansatz nicht so toll war.

Ich hatte mir folgendes Schichten-model vorgestellt:

1.) IDatenstruktur
2.) Datenstrukturklasse die grundlegende Methoden des Interfaces implementiert

3.) Business Model
4.) Erweiterte Datenstrukturklasse die auf Business Model angepasst ist.

Um die Datenstruktur flexibel zu halten, ist die unterste Schicht mit Generizitäten ausgestattet.
Umso höher man in der Schicht ist, umso weniger Generizitäten kann man setzen, da die obersten Schichten ein spezielles Problem abdecken.

Hier ein etwas aufwändigeres Beispiel, das die Problematik aber besser illustriert.

Die unterste Schicht:


    public interface IEdge<W, T, D> : IData<D>
        where W : IComparable<W>
        where T : IVertex<W, D>
    {
        W Weight { get; set; }
        T U { get; set; }
        T V { get; set; }
    }
W - Das Gewicht kann sich je nach Anwendungsfall unterscheiden (int, float, usw)
D - In diese Generizität kann eine x-beliebige Information gespeichert werden. (IData<D>)
T - Falls man eine erweiterte Datenstruktur zusammen bauen will.

 public interface IVertex<W,D> : IData<D>
        where W : IComparable<W>  
    {

        W Weight { get; set; }
        IEnumerable<IEdge<W, IVertex<W, D>, D>> Edges { get; set; }

Die Basisklasse der Datenstruktur sieht dann so aus:

  public class Edge<W, D> : IEdge<W, D>
        where W : IComparable<W>
    {

Diese Datenstruktur soll, in einem Projekt verwendet werden, das ein Schienennetz abbildet. Es gibt daher folgende Klassen "Rail" (Gleis - speichert Informationen zu Zustand, Länge, Materialtyp usw.) und "Connection" (Verbindet mehrere Gleise).

Daraus ergeben sich folgende erweiterte Datenstrukturen (ConnectionVertex und RailEdge)

    public class ConnectionVertex : Vertex<double, Connection>
    {
        public ConnectionVertex()
        {
            this._Edges = new ObservableCollection<RailEdge>(); 
        }
    }
    public class RailEdge : Edge<double, Rail>{}

Die Datenstruktur wurde Schicht für Schicht präzessiert. Algorithmen sind auf den Graphen weiterhin anwendbar, da diese sich auf IEdge und IVertex beziehen. Einzig allein das Kovarianz Problem scheint nicht lösbar zu sein.

Den aus den MSDN Link geht hervor, dass Typen mit dem out Modifizierer keinen getter oder setter haben dürfen. Somit kann ich diesen weder beim Gewicht noch anders wo hier verwenden.

Habe ich in diesem Fall die Constrains ebenfalls missbraucht wie herbivore in Datenstruktur flexibel gestalten meinte? Wie kann ich diese Grundsatz Idee am Besten realisieren? Komplett auf Generizitäten verzichten?
Dieser Beitrag wurde 3 mal editiert, zum letzten Mal von Briefkasten am .
Schaut mal im IRC vorbei:
Server: [email protected]#c#.de oder [email protected]#csharp
private Nachricht | Beiträge des Benutzers