同じユニット内に次のような2つの helper があった場合
type
TIntegerHelperA = record helper for Integer
function foo: String;
end;
TIntegerHelperB = record helper for Integer
function bar: String;
end;
function TIntegerHelperA.foo: String;
begin
Result := 'A';
end;
function TIntegerHelperB.bar: String;
begin
Result := 'B';
end;
begin
Writeln(1000000.foo); // コンパイルエラー
Writeln(1000000.bar); // OK
end.
直近の helper が有効になります。
メソッド名が違っても関係ありません。
それは helper が別のユニットにあったとしてもです。
unit Unit1;
interface
type
TIntegerHelperA = record helper for Integer
function foo: String;
end;
(略)
unit Unit2;
interface
type
TIntegerHelperB = record helper for Integer
function bar: String;
end;
(略)
uses するとき Unit2 を後にすると、TIntegerHelperA がエラーに。
uses Unit1, Unit2; begin Writeln(1000000.foo); // コンパイルエラー Writeln(1000000.bar); // OK end.
Unit1 を後にすると、TIntegerHelperB がエラーになります。
uses Unit2, Unit1; begin Writeln(1000000.foo); // OK Writeln(1000000.bar); // コンパイルエラー end.
同じメソッド名を持つ helper が定義してあると、直近の helper メソッドが呼ばれます。
意図していないメソッドが呼ばれる事が無いよう注意が必要です。
意図していないメソッドが呼ばれる事が無いよう注意が必要です。
では、次のような場合はどうなるでしょう?
type
TTest = class(TObject);
TObjectHelper = class helper for TObject
function Hello: String;
end;
TTestHelper = class helper for TTest
function Hello: String;
end;
{ TObjectHelper }
function TObjectHelper.Hello: String;
begin
Result := 'Hello, TObjectHelper';
end;
{ TTestHelper }
function TTestHelper.Hello: String;
begin
Result := 'Hello, TTestHelper';
end;
var
Test: TTest;
begin
Test := TTest.Create;
try
Writeln(Test.Hello);
finally
Test.Free;
end;
end.
この場合、コンパイルエラーにはなりません。
helper は、1つの class / record につき1つ有効なので、継承元と継承先のクラスは別個に helper を持てるからです。
上の場合、出力される値は
Hello, TTestHelper
となります。
では、さらに下記の様にキャストした場合は、どうなるでしょう?
var
Test: TTest;
begin
Test := TTest.Create;
try
Writeln(TObject(Test).Hello); // TObject にキャスト
finally
Test.Free;
end;
end.
結果は
Hello, TObjectHelper
と出力されます。 これらの事から helper はコンパイル時に決定される機構であることが判ります。
ヘルプにも
ヘルパは、識別子を解決するときに、コンパイラが使用するスコープの範囲を広げる機能です (from DocWiki)と書いてありますしね。
0 件のコメント:
コメントを投稿