2013-10-22 10 views
7

będzie się to wydawać dość proste, a może jestem po prostu brakuje trochę składni kleju ... Oto mój prosty generic (Delphi XE3) przykład:Jak używać metody rodzajowe w rodzaju pochodzącego

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. 

nie będzie podczas kompilacji "[dcc32 błąd] Unit1.pas (41): E2010 niekompatybilnych typów: 'Y' i 'X'." To jest w dół do linii:

YList = class(XList<Y>) 
end; 

Y pochodzi od X, dlaczego jest problem?

Odpowiedz

6

musiałem reimplement metody Find go naprawić w następujący sposób:

{ 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; 

What's ważne jest, aby zastąpić w rodzaju stosowanych w deklaracji zmiennej od X do T.

Wtedy właśnie przemianowany na zmienną z t do item aby uniknąć kolizji z nazwy typu zastępczego T i raplaced się Result := item przez Exit(item) wrócić znaleziony przedmiot i zamknąć metody.

+0

Świetne rzeczy @AlexSC. Pierwotnie miałem "var t: T". Zapomniałem o niewrażliwości na wielkość liter. Moje materiały generyczne C# pojawiły się na drodze! – Rob

+0

Na marginesie ... dlaczego oryginał nie działa? T pochodzi od X. – Rob

+0

@Rob: Przepraszam, nie mam na to odpowiedzi. Dla mnie kompilator zlokalizował komunikat o błędzie w ostatnim wierszu jednostki, co sugeruje, że ma coś wspólnego z instancją typu ogólnego. Wydaje się, że kompilator jest bardzo ścisły o dopasowywaniu typów, jeśli chodzi o generyczne. – AlexSC

8

Alexa odpowiedź jest poprawna rozwiązanie problemu. A także dobrze jest powrócić z funkcji, gdy tylko odpowiedź jest znana.

Chciałbym rozwinąć na odpowiedź z jakiegoś bardziej wyjaśnienia. W szczególności chciałbym odpowiedzieć na pytanie zadane w komentarzu do odpowiedzi Alex:

Na marginesie ... dlaczego oryginalne dzieło nie działa? T pochodzi od X.

Kod problemem jest tutaj:

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

Sposób myśleć o generyków, jest sobie wyobrazić, co kod wygląda podczas wystąpienia rodzaj i dostarczyć konkretny typ parametr. W tym przypadku, niech zastąpi T z Y. Następnie kod wygląda następująco:

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

Teraz masz problem na linii, która przypisuje Result:

Result := t; 

Well, Result jest typu Y, ale t jest typu X. Zależność pomiędzy X i Y jest Y pochodzi z X. Tak więc instancją Y jest X. Ale wystąpienie X nie jest Y. A więc zadanie nie jest ważne.

Jak słusznie zauważył Alex, trzeba zadeklarować zmienną pętlą być typu T. Osobiście chciałbym napisać kod jak poniżej:

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; 

ten zajmuje się również z problemem, że rutyna Szukaj pozostawia zwróconej wartości niezainicjowanymi w przypadku, gdy element nie zostanie znaleziony.Jest to problem, o którym kompilator ostrzegłby, gdy tylko uzyskasz kod do faktycznej kompilacji. Mam nadzieję, że włączycie ostrzeżenia kompilatora i radzicie sobie z nimi, kiedy się pojawią!

Powiązane problemy