Swanman's Horizon

性欲をもてあましつつなんらかの話をするよ。

メソッド解決節にジェネリックメソッドを指定できない。

たぶん

バグじゃなくて仕様なんだろうけどね。

指定できたらどうなるの?

例えばTStreamにReadInt8やReadUInt64みたいなサイズ別読み取りメソッドを実装したいときなんかに、実装部の記述量の大幅削減が期待できる。

指定できない場合

type
  THogeStream = class(TStream)
  public
    function ReadInt8: Int8;
    function ReadUInt8: UInt8;
    ...
  end;
...
function THogeStream.ReadInt8: Int8;
begin
  ReadBuffer(Result, SizeOf(Result));
end;
function THogeStream.ReadUInt8: UInt8;
begin
  ReadBuffer(Result, SizeOf(Result));
end;
...

つまり?

宣言部にある「ReadXXXX」というメソッドの数だけ同じような実装を延々と書かなきゃいけない。

指定できる場合

type
  IHogeStream = interface
    function ReadInt8: Int8;
    function ReadUInt8: UInt8;
    ...
  end;
  THogeStream = class(TStream, IHogeStream)
  public
    function QueryInterface(const IID: TGUID; out Obj): HRESULT; stdcall;
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;
    function Read<T>: T;
    function IHogeStream.ReadInt8 = Read<Int8>;
    function IHogeStream.ReadUInt8 = Read<UInt8>;
    ...
  end;
...
function THogeStream.Read<T>: T;
begin
  ReadBuffer(Result, SizeOf(T));
end;
...

つまり…?

IHogeStreamの宣言が増える、QueryInterfaceみたいなどうでもいいコードを書かないといけないという点を除けば、ReadXXXXがどれだけあろうとTHogeStreamの4つメソッド(QueryInterfaceと_AddRefと_ReleaseとRead)さえ実装すれば良い。

結局のところ

TStream自体を継承しても派生クラスは何も便利にならないので、

type
  TStreamHelper = class helper for TStream
  public
    function Read<T>: T;
  end;

とクラスヘルパーにしておいて、foo := Stream.Read; みたいにジェネリックメソッドはジェネリックメソッドのまま使うのが最強ということ。