2010-12-11 17 views
8

Delphi 2009で初めてジェネリックスを使用しようとしましたが、オブジェクトが指定されたものを実装しているかどうかを確認するために使用されるSupports関数への入力としてジェネリックタイプを使用する方法に困惑しています。インタフェース。私は問題を説明する小さなサンプルを作成しました。汎用インターフェイスタイプのSupports()関数の使用

次のタイプとユーティリティ関数を考える:私は何の問題を期待しないだろう

class procedure TFunctions.Test; 
var 
    myObject: TMyObject; 
    myInterface: IMyInterface; 
begin 
    myObject := TMyObject.Create; 

    myInterface := GetInterface<IMyInterface>(myObject); 
end; 

が、私は以下のコンパイル時エラーを取得:

IMyInterface = interface 
['{60F37191-5B95-45BC-8C14-76633826889E}'] 
end; 

TMyObject = class(TInterfacedObject, IMyInterface) 
end; 

class function TFunctions.GetInterface<T>(myObject: TObject): T; 
var 
    specificInterface: T; 
begin 
    // This would compile, but looses the generic capability 
    //Supports(myObject, IMyInterface, specificInterface); 

    // This results in compile errors 
    Supports(myObject, T, specificInterface); 

    result := specificInterface; 
end; 

と、次のコードスニペットを

[DCCエラー] GenericExample.pas(37):E2029 '('が必要ですが、 '、'が見つかりました [DCCエラー] Generate icExample.pas(37):予想E2014ステートメントが、タイプの発現は「T」を、私は、コンパイラが関数の実引数として使用する場合、私はTで行うことを期待しているかわからないんだけど

を見つけました。

私はかなり多くを検索し、これを解読できませんでした。私の一部は、コンパイル時にインターフェイス名がIID:TGUID型に変換される方法を理解できれば、具体的なインターフェイス名を使用するといくらか進歩を遂げる可能性があると私は思っています。

ご迷惑をおかけして申し訳ありません。

答えて

7

TにGUIDが関連付けられているという保証はなく、保証するためにtypeパラメータに制約を書き込む手段がありません。

インターフェイス名は、コンパイラによってシンボルテーブル内の名前を検索し、インターフェイスを表すコンパイラのデータ構造を取得し、対応するフィールドでGUIDを確認することによって、GUIDに変換されます。しかしジェネリックはC++のテンプレートに似ていません。それらはコンパイルされ型チェックされ、有効な型パラメータで動作することが知られている必要があります。これは型パラメータをその宣言に制約することを意味します。

GetTypeData(TypeInfo(T))^.GuidのようなものでRTTI(Tが実際にインターフェイスを表すことを最初にチェックする)を使用してGUIDを取得し、GUIDをそのように渡すことができます。

+0

TはGUIDを持つ特定のインターフェイスでなければならないという制約を適用できないのですか? –

+1

何らかのインターフェースが必要な場合、コードは一般的ではありません。サポートはインタフェースリファレンスを返します。コンパイラは一般的にそれがTであるものに変換することはできません。 –

+1

バリー、助けてくれてありがとう。ジェネリックプログラミングに関する私の経験は、C++のバックグラウンドからのものでしたが、インタフェース名が直接提供されているかどうかを知るのと同じ方法で、インタフェースにGuidがあるかどうかをコンパイラが知ることができると思いました。ジェネリックの<> C++テンプレートを知っているのは完璧な意味合いです。再度、感謝します。 – Chad

3

なぜあなたは迷惑ですか?

このTFunctions.GetInterfaceを使用するには次のものが必要です。

  • インタフェース
  • オブジェクト参照あなたがそれらを持っている場合は、あなただけの直接サポート()を呼び出すことができます

intf := TFunctions.GetInterface<IMyInterface>(myObject); 

は、正確には equivale NTに:ここでは、ジェネリックを使用して

Supports(IMyInterface, myObject, intf); 

は時間と労力の無駄であると本当に質問頼む「なぜそれを行うの?」。

これは、物事を読むのが難しくなっています(一般的にはジェネリックの場合と同じように)ので、使用するのが面倒です。ラッパーを作成する場合

if Supports(IMyInterface, myObject, intf) then 
    // We can use intf 

:対

intf := TFunctions.GetInterface<IMyInterface>(myObject); 
    if Assigned(intf) then 
    // ... 

:あなたは、別途ごラッパーを使用するためにテストする必要が成功/失敗を示すために便利なブール値を返します

サポート()一般的に、結果は読みやすさやユーザビリティの向上です。

imhoこれは両方のカウントで失敗し、Supports()関数自体に固執する必要があります。

+0

私の例は、具体的な質問をするために実際の文脈から逸脱しており、実際の設計を示すものではありません。 – Chad

+2

それから少なくとも文脈のいくつかを提供する必要があります。そうでなければ、あなたは運転することができず、バス運賃のためのお金を持っていないと言わずに、AからBへ行く方法を尋ねるようなものです。それは文脈の中でさえ、あなたがしていることは、それについて最善の/最も簡単な方法ではないかもしれません。特定の質問をするのはうまくやっていますが、役立つ回答が必要な場合は、重要な文脈を捨てるのは良いことではありません。 – Deltics

+2

私は正直に同意しない。乾杯。 – Chad

関連する問題