Laden...

Wie stelle ich sicher, dass Generics eine konkrete Methode besitzen?

Erstellt von Stone1984 vor 3 Jahren Letzter Beitrag vor 3 Jahren 437 Views
S
Stone1984 Themenstarter:in
7 Beiträge seit 2020
vor 3 Jahren
Wie stelle ich sicher, dass Generics eine konkrete Methode besitzen?

Guten Abend,

heute habe ich mal wieder ein Spezialproblem. Es geht um Generics und ich poste hier mal vereinfachten, beispielhaften code. Mein Hauptprogramm ist:


C test = new C();
test.data.Add(new Element() { ID = 0, NAME = "Test1" });
test.data.Add(new Element() { ID = 1, NAME = "Test2" });

C kopie = new C();
kopie = test.copy();

Hier lege ich so zu sagen das objekt Test von der Klasse C an und weiße ein paar Werte zu. Daraufhin lege ich Kopie an und lasse mir eine kopie von test ausgeben. Es soll nur das Prinzip meines Problems darstellen.

Die Klasse C sieht folgendermaßen aus:


class C:B<C, Element>
{
    public C()
    {

    }
}

public class Element
{
    public int ID { get; set; }
    public string NAME { get; set; }
}

C ist beispielsweise für eine Liste gedacht und Erbt von B, welche die Templateargumente C und Element übergeben bekommt.

Element stellt einfach ein Listenelement dar. C soll die unterste Ebene einer Liste darstellen. Es kann beispielsweise eine Liste für Autos sein, eine für Fahrräder usw.. Jede der Listen besitzt gleiche Funktionalitäten, die jedoch in der Elternklasse B algemein als Template Funktionen hinterlegt sind.

Dann kommen wir zur Klasse B:


class B<T, E>: A<E> where T: new()
{
    public B()
    {

    }

    public T copy()
    {
        T temp = new T();
        foreach (E element in data)
        {
            temp.data.Add(element);
        }
        return temp;
    }
}

In dieser Klasse wird die Kopie der aktuellen Liste angefertigt und zurückgegeben (ich weiß das macht keinen Sinn, aber soll nur prinzipiell mein Problem beschreiben). Hier tritt das nächste Problem auf. data ist nicht bekannt, obwohl es sich in der Basisklasse A von der Klasse B befindet. Es wird die Fehlermeldung:

Fehlermeldung:
Fehler CS1061 "T" enthält keine Definition für "data", und es konnte keine zugängliche data-Erweiterungsmethode gefunden werden, die ein erstes Argument vom Typ "T" akzeptiert (möglicherweise fehlt eine using-Direktive oder ein Assemblyverweis).

ausgegeben.

Die Basisklasse hat die folgende Form:

    
class A<E>
{
    public A()
    {
        data = new ObservableCollection<E>();
    }

     public ObservableCollection<E> data { get; set; }
}

In der Basisklasse ist data public und es ist ein get und set möglich. Durch die ObservableCollection muss auch das Add() möglich sein. Mir ist derzeit unklar wie ich diesen Fehler, das data nicht erkannt wird beheben kann. Hat an diesem Punkt jemand eine Idee?

Vielen Dank schon mal im Voraus.

16.834 Beiträge seit 2008
vor 3 Jahren

Es ist immer schwer als Helfer mit konstruierten Problemen zu verstehen, was der eigentliche Zweck Deines Problem ist bzw. für welchen Sinn das Dienen soll.
Daher macht es besonders im Internet immer sinn, dass man das nicht tut sondern den Zweck erklärt, was man vor hat.
Meistens sind die Probleme nämlich an der Wurzel und wir behandeln hier nur ein Symptom.

Die Ursache Deiner Fehlermeldung liegt in der Copy-Methode.
Es gibt ganz ganz ganz arg wenige Fälle, bei denen man ein Objekt wirklich kopieren muss - und alle anderen Fälle sind ganz einfache Workarounds für Programmier- oder Architekturfehler.

Die Fehlermeldung selbst sagt, dass der Typ T kein data Property hat; und hat er hier auch nicht - Du gibst das nirgends bekannt.
Die einzige Information, die T hier hat ist die new() Einschränkung, also dass das Target einen public-parameterlosen Konstruktor haben muss.
Du gibst nirgends an, dass T eine gewisse Klasse darstellt oder sich auf ein Interface bezieht, das die Eigenschaft data hat.

Wenn man sowas sieht

class C:B<C, Element>

dann vermute ich auch, dass Du die Generics noch nich so 100% verstanden hast 😉

Durch die Vererbung macht das Copy über ein Generic ohnehin nich so wirklich sinn.
Man würde es einfach in der Basis-Klasse implementieren.

PS: wenn Du schon mit C# programmierst, dann orientier Dich doch wenigstens ein bisschen an die übliche Schreibweise von C#.
[Artikel] C#: Richtlinien für die Namensvergabe
Sieht ja sonst aus wie ein Mix aus Kraut und Rüben 😉

S
Stone1984 Themenstarter:in
7 Beiträge seit 2020
vor 3 Jahren

Vielen Dank Abt für den Hinweis. Dadurch habe ich jetzt die Lösung gefunden. Und habe das Interface


interface IA<E>
{
    ObservableCollection<E> data { get; set; }
}

erstellt und für die Klasse A bereitgestellt


class A<E>: IA<E>
{
....

und mit der Klasse B bekannt gemacht.


class B<T, E>: A<E> where T: IA<E>, new()
{
....

Damit läuft es jetzt so wie es soll.

Dass das kopieren wenig Sinn macht, das weiß ich. Ich habe nur nach einem vereinfachten Beispiel für mein Problem gesucht, denn der Code den ich sonst hätte wäre viel zu lang.

Den Punkt mit der Benennung muss ich mir mal genauer anschauen und dann das nächste Mal verwenden. Auf jeden Fall vielen Dank für die nützliche Antwort.