2013-10-22 18 views
7

Dies wäre ziemlich einfach erscheinen und vielleicht bin ich nur ein wenig Syntax Kleber fehlt ... Hier ist meine einfache generische (Delphi XE3) Beispiel:Wie kann ich eine generische Methode in einem abgeleiteten Typ verwenden

unit Unit1; 

interface 

uses 
    generics.collections; 

type 

X = class 
public 
    Id: Integer; 
end; 

XList<T : X> = class(TObjectList<T>) 
function Find(Id: Integer) : T; 
end; 

Y = class(X) 

end; 

YList = class(XList<Y>) 
end; 

implementation 

{ XList<T> } 

function XList<T>.Find(Id: Integer): T; 
var 
    t: X; 
begin 
    for t in Self do 
    if t.Id = Id then 
     Result := t; 
end; 

end. 

Dies wird nicht kompiliert mit "[dcc32 Fehler] Unit1.pas (41): E2010 Inkompatible Typen: 'Y' und 'X'". Es liegt an der Linie:

YList = class(XList<Y>) 
end; 

Y stammt von X also warum gibt es ein Problem?

Antwort

6

Ich hatte die Find-Methode neu zu implementieren, wie es zu beheben folgt:

{ XList<T> } 

function XList<T>.Find(Id: Integer): T; 
var 
    item: T; 
begin 
    for item in Self do 
    if item.Id = Id then 
     Exit(item); 
    Result := nil; 
end; 

Was ist hier wichtig ist die Art in der Variablendeklaration X-T zu ersetzen.

Dann umbenannt ich nur die Variable aus t zu itemT einen Namen Kollision mit dem Typ Platzhalter zu vermeiden und raplaced die Result := item von Exit(item) das gefundene Element zurückzukehren und das Verfahren zu beenden.

+0

Großartiges Zeug @AlexSC. Ich hatte ursprünglich "var t: T". Ich hatte die Groß-/Kleinschreibung vergessen. Mein C# -Generika-Zeug ist da im Weg! – Rob

+0

Nebenbei ... warum funktioniert das Original nicht? T ist abgeleitet von X. – Rob

+0

@Rob: Entschuldigung, ich habe keine Antwort dafür. Für mich hat der Compiler die Fehlermeldung in der letzten Zeile der Unit gefunden, was mich vermuten lässt, dass es etwas mit der generischen Instanziierung zu tun hat. Es scheint, dass der Compiler sehr streng ist, wenn es um Generika geht. – AlexSC

8

Alex Antwort ist die richtige Lösung für das Problem. Und es ist auch gut, von der Funktion zurückzukehren, sobald die Antwort bekannt ist.

Ich möchte auf die Antwort mit etwas mehr Erklärung erweitern. Insbesondere möchte ich die Frage beantworten, die Sie in den Kommentaren zu Alex 'Antwort gestellt haben:

Als Nebensache ... warum funktioniert das Original nicht? T ist abgeleitet von X.

Der Code Problem ist hier:

function XList<T>.Find(Id: Integer): T; 
var 
    t: X; 
begin 
    for t in Self do 
    if t.Id = Id then 
     Result := t; 
end; 

Die Art und Weise über Generika zu denken, ist, sich vorzustellen, wie der Code aussieht, wenn Sie den Typ instanziiert und einen konkreten Typ liefern Parameter. In diesem Fall ersetzen wir T durch Y. Dann sieht der Code wie folgt aus:

function XList_Y.Find(Id: Integer): Y; 
var 
    t: X; 
begin 
    for t in Self do 
    if t.Id = Id then 
     Result := t; 
end; 

Jetzt haben Sie ein Problem an der Linie haben, die Result zuweist:

Result := t; 

Nun, Result vom Typ Y, aber t ist vom Typ X. Die Beziehung zwischen X und Y besteht darin, dass Y von X abgeleitet ist. Eine Instanz von Y ist also eine X. Aber eine Instanz von X ist keine Y. Und so ist die Zuordnung nicht gültig.

Wie Alex richtig angemerkt hat, müssen Sie die Loop-Variable vom Typ T deklarieren. Persönlich würde ich den Code wie folgt schreiben:

function XList<T>.Find(Id: Integer): T; 
begin 
    for Result in Self do 
    if Result.Id = Id then 
     exit; 
    Result := nil; 
    // or perhaps you wish to raise an exception if the item cannot be found 
end; 

Diese befasst sich auch mit dem Problem, dass Ihre Suchroutine verlässt ihren Rückgabewert, falls nicht initialisierte das Element nicht gefunden.Das ist ein Problem, vor dem der Compiler gewarnt hätte, sobald Sie den Code soweit kompiliert haben. Ich hoffe, Sie aktivieren Compiler-Warnungen und behandeln sie, wenn sie erscheinen!