はじめに
Delphi には 2006 からクラスヘルパとレコードヘルパがあり、既存のクラスやレコード (構造体) を継承する事なく拡張する機能があります。あ、レコード (構造体) はそもそも継承できないんですけどね。
そして Delphi XE4 において普通の型ですらレコードヘルパで拡張できるようになりました。10.2 Tokyo 時点では以下のような組み込み型ヘルパがあります。
レコードヘルパ | 説明 |
---|---|
TBooleanHelper | TBooleanHelper は、Boolean 型の機能を提供するレコード ヘルパです。 |
TByteBoolHelper | TByteBoolHelper は、ByteBool 型の機能を提供するレコード ヘルパです。 |
TByteHelper | TByteHelper は、Byte 型の機能を提供するレコード ヘルパです。 |
TCardinalHelper | TCardinalHelper は、Cardinal 型の機能を提供するレコード ヘルパです。 |
TDoubleHelper | 単精度浮動小数点値の低レベル操作の実行をサポートします。 |
TExtendedHelper | 拡張精度(Extended 型)浮動小数点値に対する低レベル演算を実行できるようにします。 |
TGuidHelper | TGUID のヘルパ型です。 |
TInt64Helper | TInt64Helper は、Int64 型の機能を提供するレコード ヘルパです。 |
TIntegerHelper | TNativeUIntHelper は、NativeUInt 型の機能を提供するレコード ヘルパです。 |
TLongBoolHelper | TLongBoolHelper は、LongBool 型の機能を提供するレコード ヘルパです。 |
TNativeIntHelper | TNativeIntHelper は、NativeInt 型の機能を提供するレコード ヘルパです。 |
TNativeUIntHelper | TNativeUIntHelper は、NativeUInt 型の機能を提供するレコード ヘルパです。 |
TShortIntHelper | TShortIntHelper は、ShortInt 型の機能を提供するレコード ヘルパです。 |
TSmallIntHelper | TSmallIntHelper は、SmallInt 型の機能を提供するレコード ヘルパです。 |
TStringHelper | インデックスが 1 から始まる文字列もインデックスが 0 から始まる文字列も含むすべての文字列扱うための関数やプロパティを提供するレコード ヘルパです。 |
TUInt64Helper | TUInt64Helper は、UInt64 型の機能を提供するレコード ヘルパです。 |
TWordBoolHelper | TWordBoolHelper は、WordBool 型の機能を提供するレコード ヘルパです。 |
TWordHelper | TWordHelper は、Word 型の機能を提供するレコード ヘルパです。 |
例えば以前は IntToStr() を使って数値->文字列変換しなくてはなりませんでした。
var
i: Integer;
s: string;
begin
i := 100;
s := IntToStr(i);
end;
現在では以下のように書けます。
var
i: Integer;
s: string;
begin
i := 100;
s := i.ToString;
end;
コード補完が効くので便利ですね。
レコードヘルパを自作する
例えば TDateTime 型の実体は Double 型です。T が頭にありますがレコード (構造体) ではないため、Delphi XE4 より前ではヘルパが作れませんでしたが、今なら?
unit uDateTime;
interface
uses
System.SysUtils, System.DateUtils;
type
TDayOfWeek = (Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday);
TDayOfWeekHelper = record helper for TDayOfWeek
function ToInteger: Integer;
end;
TDateTimeHelper = record helper for TDateTime
function AddDays(Value: Word): TDateTime;
function AddHours(Value: Word): TDateTime;
function AddMilliseconds(Value: Word): TDateTime;
function AddMinutes(Value: Word): TDateTime;
function AddMonths(Value: Word): TDateTime;
function AddSeconds(Value: Word): TDateTime;
function AddYears(Value: Word): TDateTime;
function Date: TDateTime;
function Day: Word;
function DayOfWeek: TDayOfWeek;
function DayOfYear: Word;
function DaysInMonth(const AYear, AMonth: Word): Word;
function Hour: Word;
function IsLeapYear(Year: Word): Boolean;
function Millisecond: Word;
function Minute: Word;
function Month: Word;
function Now: TDateTime;
function Parse(const S: string): TDateTime; overload;
function Parse(const S: string; const AFormatSettings: TFormatSettings): TDateTime; overload;
function Second: Word;
function Ticks: Int64;
function TimeOfDay: TDateTime;
function Today: TDateTime;
function ToString(const Format: string = ''): string;
function TryParse(const S: string; out Value: TDateTime): Boolean; overload;
function TryParse(const S: string; out Value: TDateTime; const AFormatSettings: TFormatSettings): Boolean; overload;
function Year: Word;
end;
implementation
{ TDateTimeHelper }
function TDateTimeHelper.AddDays(Value: Word): TDateTime;
begin
result := System.DateUtils.IncDay(Value);
end;
function TDateTimeHelper.AddHours(Value: Word): TDateTime;
begin
result := System.DateUtils.IncHour(Value);
end;
function TDateTimeHelper.AddMilliseconds(Value: Word): TDateTime;
begin
result := System.DateUtils.IncMilliSecond(Value);
end;
function TDateTimeHelper.AddMinutes(Value: Word): TDateTime;
begin
result := System.DateUtils.IncMinute(Value);
end;
function TDateTimeHelper.AddMonths(Value: Word): TDateTime;
begin
result := System.SysUtils.IncMonth(Value);
end;
function TDateTimeHelper.AddSeconds(Value: Word): TDateTime;
begin
result := System.DateUtils.IncSecond(Value);
end;
function TDateTimeHelper.AddYears(Value: Word): TDateTime;
begin
result := System.DateUtils.IncYear(Value);
end;
function TDateTimeHelper.Date: TDateTime;
begin
result := System.DateUtils.DateOf(Self);
end;
function TDateTimeHelper.Day: Word;
begin
result := System.DateUtils.DayOf(Self);
end;
function TDateTimeHelper.DayOfWeek: TDayOfWeek;
begin
result := TDayOfWeek(System.SysUtils.DayOfWeek(Self) - 1);
end;
function TDateTimeHelper.DayOfYear: Word;
begin
result := System.DateUtils.DayOfTheYear(Self);
end;
function TDateTimeHelper.DaysInMonth(const AYear, AMonth: Word): Word;
begin
result := System.DateUtils.DaysInAMonth(AYear, AMonth);
end;
function TDateTimeHelper.Hour: Word;
begin
result := System.DateUtils.HourOf(Self);
end;
function TDateTimeHelper.IsLeapYear(Year: Word): Boolean;
begin
result := System.SysUtils.IsLeapYear(Year);
end;
function TDateTimeHelper.Millisecond: Word;
begin
result := System.DateUtils.MilliSecondOf(Self);
end;
function TDateTimeHelper.Minute: Word;
begin
result := System.DateUtils.MinuteOf(Self);
end;
function TDateTimeHelper.Month: Word;
begin
result := System.DateUtils.MonthOf(Self);
end;
function TDateTimeHelper.Now: TDateTime;
begin
result := System.SysUtils.Now;
end;
function TDateTimeHelper.Parse(const S: string; const AFormatSettings: TFormatSettings): TDateTime;
begin
result := System.SysUtils.StrToDateTime(S, AFormatSettings);
end;
function TDateTimeHelper.Second: Word;
begin
result := System.DateUtils.SecondOf(Self);
end;
function TDateTimeHelper.Parse(const S: string): TDateTime;
begin
result := System.SysUtils.StrToDateTime(S);
end;
function TDateTimeHelper.Ticks: Int64;
begin
result := System.DateUtils.MilliSecondOf(Self) * 10000;
end;
function TDateTimeHelper.TimeOfDay: TDateTime;
begin
result := System.DateUtils.TimeOf(Self);
end;
function TDateTimeHelper.Today: TDateTime;
begin
result := System.DateUtils.Today;
end;
function TDateTimeHelper.ToString(const Format: string): string;
begin
if Format = '' then
result := System.SysUtils.DateTimeToStr(Self)
else
result := System.SysUtils.FormatDateTime(Format, Self)
end;
function TDateTimeHelper.TryParse(const S: string; out Value: TDateTime;
const AFormatSettings: TFormatSettings): Boolean;
begin
result := System.SysUtils.TryStrToDateTime(S, Value, AFormatSettings);
end;
function TDateTimeHelper.TryParse(const S: string; out Value: TDateTime): Boolean;
begin
result := System.SysUtils.TryStrToDateTime(S, Value);
end;
function TDateTimeHelper.Year: Word;
begin
result := System.DateUtils.YearOf(Self);
end;
{ TDayOfWeekHelper }
function TDayOfWeekHelper.ToInteger: Integer;
begin
result := Ord(Self);
end;
end.
.NET の DateTime 構造体 をパクったインスパイアしたレコードヘルパも簡単に作れます。
使い方は uses 句にこのユニットを追加するだけです。
uses
..., uDateTime;
おわりに
この XE4 から拡張されたレコードヘルパは列挙型等に対しても使えます。上の uDateTime.pas では TDayOfWeek 列挙型に対するレコードヘルパ TDayOfWeekHelper がありますね。
var
s: string;
begin
s := Now.DayOfWeek.ToInteger.ToString;
end;
このコードは今日の曜日を表す TDayOfWeek を数値に変換したものを文字列に変換しています。今日が日曜日の場合、S には '0' が入ります (6=土曜日)。
従来からのレコードヘルパーも含め、この機能は Fortran 2003 や Oberon-2 でいう所の Type-Bound Procedures に近い考え方だと思います。
Delphi 11.0 Alexandria で、TDatetime 型に対するレコードヘルパ (System.DateUtils.TDateTimeHelper) が追加されました。
See also: