Delphi中的重复setters逻辑

Delphi中的重复setters逻辑,delphi,pascal,delphi-2006,Delphi,Pascal,Delphi 2006,对于类的每个setter,我必须实现一些事件逻辑(onchange,OnChanged): 您能建议一种方法来实现这一点,而不必为每个setter重复所有这些行吗?您可以添加一个额外的方法。比如: procedure TBlock.setValue(const Value : Double; Location : PDouble); var OldValue : Double; begin OldValue:=Location^; DoOnChanging(OldValue,Va

对于类的每个setter,我必须实现一些事件逻辑(onchange,OnChanged):


您能建议一种方法来实现这一点,而不必为每个setter重复所有这些行吗?

您可以添加一个额外的方法。比如:

procedure TBlock.setValue(const Value : Double; Location : PDouble);
var
  OldValue : Double;
begin
   OldValue:=Location^;
   DoOnChanging(OldValue,Value);
   Location^:=Value;
   DOnChanged(OldValue, Value);
end;

procedure TBlock.setWeightOut(const Value : Double);
begin
  setValue(value, @FWeightOut);
end;
但是我还没有编译/测试代码。其想法是使用一个通用的setter方法,该方法使用指向该位置的指针。专门化版本只调用gerneral方法,并设置变量的地址。 但是,每种类型的变量(双精度、整数等)必须有一种通用setter方法。您可以修改它以处理指针和变量长度,以处理所有类型—如果值得的话,由您决定。

尝试以下方法:

procedure TBlock.SetField(var Field: Double; const Value: Double);
var
    OldValue: Double;
begin
    OldValue := Field;
    DoOnChanging(OldValue, Value);
    Field := Value;
    DoOnChanged(OldValue, Value);
end;

procedure TBlock.SetWeightIn(const Value: Double);
begin
    SetField(FWeightIn, Value);
end;

procedure TBlock.SetWeightOut(const Value: Double);
begin
    SetField(FWeightOut, Value);
end;
Delphi支持索引属性。多个属性可以共享一个getter或setter,由顺序索引区分:

type
  TWeightType = (wtIn, wtOut);
  TBlock = class
  private
    procedure SetWeight(Index: TWeightType; const Value: Double);
    function GetWeight(Index: TWeightType): Double;
  public
    property InWeight: Double index wtIn read GetWeight write SetWeight;
    property OutWeight: Double index wtOut read GetWeight write SetWeight;
  end;
您可以将此与组合以获得以下结果:

procedure TBlock.SetWeight(Index: TWeightType; const Value: Double);
begin
  case Index of
    wtIn: SetField(FWeightIn, Value);
    wtOut: SetField(FWeightOut, Value);
  end;
end;

这可能会为您提供通过索引引用字段的其他方法,而不是为此类相关值提供两个完全独立的字段。

如果过程/函数的参数相同,并且开始和结束之间的代码相同,则可以使用

procedure SetWeightValue(const Value: Double);
var OldValue: Double;
begin
  OldValue := FWeightIn;
  DoOnChanging(OldValue, Value);
  FWeightIn := Value;
  DoOnChanged(OldValue, Value);
end;

这就是…

+1在基于事件的编程中经常会遇到的一般问题。您应该首先检查该值OldValue,这是整个VCL中常用的习惯用法。无论是在方法开始时,还是在OnChange事件之后(取决于OnChange是否获取var参数,即它是否可以更改新值)。您应该像Cobus Kruger的建议那样使用var参数,而不是指针。@Tobias:不,不仅仅是语法糖。使用var参数不可能传递空指针,因此SetValue()方法不必检查它(顺便说一句,您的代码不需要!)。一个不太可能被误用的API就更好了。事实上,这和我的解决方案一样,只是语法更好。不仅仅是语法更好,Tobias。有效语法。我输入错误-我只是使用了类型而不是变量名。我更正了我的示例,因为我手头没有编译器。正如您所看到的,这是一种有效的语法。这个想法保持不变。传递地址(通过指针或使用var)。编译器也会这样做。在二进制级别上,结果是相同的——只是语法比我前面说的更好。它甚至不容易使用。我几乎给出了+1的答案,但我认为它太长了。看来还是可以简明扼要地描述一下:-)
procedure SetWeightValue(const Value: Double);
var OldValue: Double;
begin
  OldValue := FWeightIn;
  DoOnChanging(OldValue, Value);
  FWeightIn := Value;
  DoOnChanged(OldValue, Value);
end;