有没有办法缩短is / as结构?

时间:2015-06-01 16:23:33

标签: delphi

我想缩短以下代码:

procedure TAddInModule.FinanBladCalculate(Sender: TObject);
begin
  if (Sender is TExcelWorksheet) then begin
    (Sender as TExcelWorksheet).Tag:= TagCalculationDone;
    // or
    TExcelWorksheet(Sender).Tag:= TagCalculationDone;
  end
  else {do nothing}
end;

我做了很多这是/作为检查,只是为了安全起见 然而,这是很多打字,只是为了安全演员。

有没有办法缩短这个并获得相同的结果? 我正在考虑使用记录和运算符重载的通用解决方案。

以下代码有效:

program Project41;
{$APPTYPE CONSOLE} 
uses
  System.SysUtils,VCL.Forms;

type
  AsIs<T: class> = record
    Data: T;
    class operator Implicit(const a: TObject): AsIs<T>;
    function OK: boolean;
  end;

function AsIs<T>.OK: boolean;
begin
  Result:= Assigned(Data);
end;

class operator AsIs<T>.Implicit(const a: TObject): AsIs<T>;
begin
  if a is T then Result.Data:= T(a)
  else Result.Data:= nil;
end;

procedure Demonstrate(Sender: TObject);
var
  Test: AsIs<TApplication>;
begin //Something silly to demonstrate
  Test:= Sender;
  if Test.OK then Test.Data.HandleMessage;
end;

begin 
  Demonstrate(Application);
end.

有没有办法让它更短? 类似的东西:

  Test(App).Data.HandleMessage;
  //or even
  Test(App).HandleMessage;

2 个答案:

答案 0 :(得分:6)

有一种观点认为,代码应该将GUI和逻辑分开,就像在MVC模式中一样,因此事件处理程序不应包含任何实际工作,而只是将用户的活动路由到实际的业务逻辑实现者,如

procedure TAddInModule.Button1Click(Sender: TObject);
begin
  if (Sender is TExcelWorksheet) then 
     FinanBladCalculate(TExcelWorksheet(Sender));
end;

procedure TAddInModule.FinanBladCalculate(Sheet: TExcelWorksheet);
begin
  Sheet.Tag:= TagCalculationDone;
  ...
  ...
  ...
end;

这样以后会有更多的事件可以调用FinanBladCalculate,实际工作负载集中并包含在那里(如菜单,热键,手势等)。

这种模式可能会在一定程度上使用该记录

procedure TAddInModule.Button1Click(Sender: TObject);
begin
  FinanBladCalculate(Sender);
end;

procedure TAddInModule.MenuItem1Click(Sender: TObject);
begin
  FinanBladCalculate(Sender);
end;

procedure TAddInModule.CheckBox1Check(Sender: TObject);
begin
  FinanBladCalculate(Sender);
end;

....

procedure TAddInModule.FinanBladCalculate(const Sheet: AsIs<TExcelWorksheet>);
begin
  if Sheet.Data = nil then exit;

  Sheet.Data.Tag:= TagCalculationDone;
  ...
  ...
  ...
end;

如果您有许多可以启动某些工作并具有不同事件处理程序的GUI元素,那么这可能是有意义的。

答案 1 :(得分:6)

使用绝对。您仍然可以执行确保类型安全所需的警告,但绝对允许您使用声明性类型转换与内联类型转换或作为与其隐式,冗余检查(如果您自己检查 类型,则是多余的):

var
  excel: TExcelWorksheet absolute aSender;
begin
  if aSender is TExcelWorksheet then
  begin
    excel.Tag := TagCalculationDone;
  end;
end;

绝对声明使 excel 成为声明中引用的内存地址的类型同义词。即,没有额外的局部变量,也没有执行类型转换为该变量赋值的代码。而 excel 只是访问 aSender 价值的另一种方式。

您可以根据需要为同一地址添加任意数量的同义词同义词。因此,如果 aSender 也可以是 TWordDocument (或其他):

var
  excel: TExcelWorksheet absolute aSender;
  word: TWordDocument absolute aSender;
begin
  if aSender is TExcelWorksheet then
  begin
    excel.Tag := TagCalculationDone;
  end
  else if aSender is TWordDocument then
  begin
    word.Tag := TagFieldsUpdated;  // Or whatever
  end;
end;

可以使用相同的技术为局部变量和参数创建此类同义词。