2011年11月10日

クラスヘルパ

クラスヘルパはDelphi 2007で導入された新機能で、クラスを継承することなく拡張するためのものです(Delphi 2007 HandbookにはDelphi 2007でDelphi 2006とのバイナリレベルでの互換性を確保するために導入された、とあります)。当初はクラスにしか適用できませんでしたが、Delphi 2010以降ではレコード型に対しても(レコードヘルパとして)適用することができます。しかしヘルパで定義したメソッドではpublicメンバにしかアクセスできないため、ある種のシンタックスシュガーのように考えればよいと思っていました。DelphiデベロッパチームシニアソフトウェアデベロッパのMat DeLongさん Mat DeLongさんのこのアーティクルを読むまでは。

Mat DeLong : Gaining access to private fields of a class Gaining access to private fields of a class in Delphi | Mat DeLong

これによると、private/protectedメンバであっても"Self."で修飾することでアクセスできる、と書かれています。なんですと?ということでDelphi 2007以降の各バージョンで確認してみました。
  • Delphi 2007: "Self."の有無に関わらずpublicのみアクセス可能
  • Delphi 2009: "Self."とすることでprivateはアクセスできるがなぜかprotectedはアクセス不可
  • Delphi 2010/XE/XE2: "Self."とすることでprivate/protectedもアクセス可能
Delphi 2010以降であればこの方法でより突っ込んだことができそうです。

またクラス ヘルパとレコード ヘルパ(Delphi)には

ただし、ソース コードの任意の場所で適用されるヘルパの数は、0 または 1 つだけです。
とあり、ひとつのクラスに複数のヘルパを適用することはできないのですが、ヘルパの構文として

type
  identifierName = class|record helper [(ancestor list)] for TypeIdentifierName
    memberList
  end;
とあり、継承したクラスヘルパを作成することで実質的に複数のヘルパを適用することができます。
type
  TFooHelper = class helper for TFoo
  public
    procedure Bar1;
  end;

  TFooHelperEx = class helper (TFooHelper) for TFoo
  public
    procedure Bar2;
  end;

var
  Foo: TFoo;
begin
  ...
  Foo.Bar1;  // TFooHelper.Bar1
  Foo.Bar2;  // TFooHelperEx.Bar2
  ...

こんな感じです。

2020/09/23追記: Mat DeLongさんの記事のリンクを更新しました。pmcgeeさん、情報ありがとうございます。

2 件のコメント:

pmcgee さんのコメント...

Mat DeLong now ... https://mathewdelong.wordpress.com/2011/11/08/gaining-access-to-private-fields-of-a-class-in-delphi/

ふー さんのコメント...

Hi pmcgee, Thank you for your information. I update some links.