Swanman's Horizon

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

TEncodingを拡張する。

普段から何かとデフォルト文字コードがShiftJISだったりして、DelphiでもShiftJISを扱いたい。だけどDelphiで使おうと思ったら、

var
  enc: TEncoding;
begin
  enc := TEncoding.GetEncoding(932);
  try
    // ShiftJISを扱う処理
  finally
    enc.Free;
  end;
end;

などといちいち生成して解放してやる必要があって(起動時辺りに作っておいて使いまわしてもいいけど)、やたらめんどくさい。
だからこうする。

unit Lyna.Strings;

interface

uses
  Windows, SysUtils;

type
  TEncodingHelper = class helper for TEncoding
  strict private
    class var
      FSJISEncoding: TEncoding;
    class function GetSJIS: TEncoding; static;
  private
    class procedure FreeHelperEncodings;
  public
    class property SJIS: TEncoding read GetSJIS;
  end;

implementation

{ TEncodingHelper }

class procedure TEncodingHelper.FreeHelperEncodings;
begin
  FreeAndNil(FSJISEncoding);
end;

class function TEncodingHelper.GetSJIS: TEncoding;
var
  LEncoding: TEncoding;
begin
  if FSJISEncoding = nil then
  begin
    LEncoding := TMBCSEncoding.Create(932);
    if InterlockedCompareExchangePointer(Pointer(FSJISEncoding), LEncoding, nil) <> nil then
      LEncoding.Free;
  end;
  Result := FSJISEncoding;
end;

initialization
finalization
  TEncoding.FreeHelperEncodings;
end.

あとはこのユニットをusesしてやれば、TEncoding.SJISプロパティが使えるようになるという仕組み。クラスヘルパーばんじゃい。これは単なる例なので、EUC-JPやらJISやらEUC-KRやらBig-5なんかを追加してみたりすると実用的。

正直なところを言えば解放処理はclass destructorでやりたかったんだけど、クラスヘルパーで宣言しても呼び出してくれないみたい。使えねえ仕様だ…。このせいで苦肉の策としてfinalization部を使わざるを得ず。あ、もちろん使い方はTEncoding.ASCIIやTEncoding.UTF8といったのと同じでございます。

しかしなー、どうせプログラム内ではひとつのコードページに対してひとつインスタンスがあればいいんだから*1、GetEncoding内でまだ生成されてなければ内部リストに追加して返す、生成されてたらリストから探して返す、そして終了時に全部一括解放、みたいにしてくれれば使いやすかったのに。.NETから色々パクるのは正直便利になっていいんだけど、GCがないって前提で移植してくれないと利便性さがりまくりんぐだよ。

*1:実際クラスプロパティであるASCIIやらUnicode、UTF8等はそうなってるわけだし