Edited at

【Delphi】クラスヘルパによる private メンバアクセスの件を with 文で回避できると聞いて


はじめに

Delphi ではクラスヘルパを使うと裏技的にクラスの private メンバにアクセスできました。

最初期のクラスヘルパは Delphi のバージョン 2006 で実装されましたが、この裏技は Delphi 2009 辺りから使えるようになりました。


改悪

ところがこのクラスヘルパを使った裏技は 10.1 Berlin で封じられてしまいました。


可視性のセマンティクスを実行するため、クラス ヘルパやレコード ヘルパでは、拡張元のクラスやレコードの private メンバにはアクセスできません。


それまで使えていたものがいきなり使えなくなったため非難轟々でした。


回避策1

回避策の一つ目はインラインアセンブラで記述するというものです。


回避策2

最近見つかった回避策は With 文を使う方法です。RSP-15237 のコメ欄にこう書いてあります。


In a helper for class SomeClass with a private property SomeValue,

Self.SomeValue don't works

With Self do SomeValue :=... works

Is it a bug or something you allowed for some obscur reason ?



検証

拙作の Value Calc プロパティエディタ で検証してみます。これは IDE 用の拡張で...説明が面倒なので、詳しくは以下の動画に譲ります。

この拡張は 10.1 Berlin 対応時に、インラインアセンブラのコードを追加して問題を回避していました。


uPropEditorHelper.pas


{$IFDEF USEMULTIEXP}
function TPropertyEditorHelper.GetPropList: PInstPropList;
{$IF CompilerVersion < 31.0}
begin
Result := Self.FPropList;
end;
{$ELSE}
// http://d.hatena.ne.jp/tales/20160420/1461081751
asm
MOV EAX, Self.FPropList;
end;
{$IFEND}
{$ENDIF}

この部分を with 文で回避してみます。


uPropEditorHelper.pas

{$IFDEF USEMULTIEXP}

function TPropertyEditorHelper.GetPropList: PInstPropList;
begin
with Self do
Result := FPropList;
end;
{$ENDIF}

あら簡単。


おわりに

そのうち先述の回避策も潰されてしまうのかもしれませんが、ユーザーの意見を聞いてコンパイラ指令で使用の有無を切り替えられるようにしたらいいんじゃないかと思います。