7

これはかなり単純に見えますが、構文の接着剤が少し欠けているだけかもしれません...これが私の単純な一般的な(Delphi XE3)の例です:

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.

これは、「[dcc32 エラー] Unit1.pas(41): E2010 Incompatible types: 'Y' and 'X'」でコンパイルされません。それは次の行までです。

YList = class(XList<Y>)
end;

Y は X から派生しているのに、なぜ問題があるのでしょうか?

4

2 に答える 2

8

アレックスの答えは、問題に対する正しい解決策です。また、答えがわかったらすぐに関数から戻ることも有効です。

もう少し説明を加えて答えを広げたいと思います。特に、アレックスの回答に対するコメントであなたが尋ねた質問に答えたいと思います。

余談ですが…なぜ原作は動かないのでしょうか?T は X から派生します。

問題のコードは次のとおりです。

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

ジェネリックについて考える方法は、型をインスタンス化し、具体的な型パラメーターを指定したときにコードがどのように見えるかを想像することです。Tこの場合は で代用しましょうY。次に、コードは次のようになります。

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

に割り当てる行に問題がありますResult

Result := t;

ResultはタイプですYt、タイプはXです。Xとの関係YYから派生したものXです。したがって、のインスタンスはYですX。しかし、 のインスタンスは でXはありませんY。したがって、割り当ては無効です。

Alex が正しく指摘したように、ループ変数を型として宣言する必要がありますT。個人的には、次のようなコードを書きます。

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;

これは、アイテムが見つからない場合に検索ルーチンが戻り値を初期化しないままにするという問題にも対処します。これは、実際にコンパイルする限り、コードを取得するとコンパイラが警告する問題です。コンパイラの警告を有効にして、警告が表示されたら対処してください!

于 2013-10-22T12:02:23.047 に答える