班级成员在任职时没有变更

时间:2015-01-07 16:03:07

标签: delphi

我有以下设置:

//code from unit
...
TObjectList<T:TObject>=class(TObject)
private
  function GetItem(Name: string): T;
  function GetItemByIndex(Index: Integer): T;
public
  property Items[Name:string]:T read GetItem;default;
  property Item[Index:Integer]:T read GetItemByIndex;
end;

...
{ TObjectList<T> }

function TObjectList<T>.GetItem(Name: string): T;
begin
Result:=T(FindComponent(Name));
end;

function TObjectList<T>.GetItemByIndex(Index: Integer): T;
begin
Result:=T(Components[Index]);
end;
...
TStringEval=record
private
  FValue:string;
public
  function AsString:string;
  function AsInteger:Integer;
  function AsFloat:Double;
  function AsBoolean:Boolean;
  function AsDateTime:TDateTime;
  function AsHex:string;
  procedure SetValue(const S:string);overload;
  procedure SetValue(const I:Integer;const AsHex:boolean=false);overload;
  procedure SetValue(const F:Double);overload;
  procedure SetValue(const B:Boolean);overload;
  procedure SetValue(const D:TDateTime);overload;
...
TConsoleVariable=class(TConsoleCommand)
...
  property Value:TStringEval read GetValue write SetValue;
...
TConsole=class(TObjectList<TConsoleCommand>)
...
  property Variables[Name:string]:TConsoleVariable read GetVariable;
...

function TConsole.GetVariable(Name: string): TConsoleVariable;
begin
Result:=TConsoleVariable(Items[Name]);
end;
...
//main application code, the troublesome line.
Console.Variables['developer'].Value.SetValue(MESSAGELEVEL_VERBOSE);
...

这行不会因为我无法理解的原因而改变变量的值。我的代码的其他部分也存在类似的问题。控制台变量最初由控制台本身分配值1。我想暂时将其设置得更高,以便从应用程序获得更详细的输出,而无需重新编译控制台代码(它在一个软件包中)。

1 个答案:

答案 0 :(得分:5)

这是因为您没有更改存储的值,而是更改了它的副本。

Console.Variables['developer'].Value.SetValue(MESSAGELEVEL_VERBOSE);

这是尝试进行修改的代码。 TStringEval实例由Value属性生成:

property Value: TStringEval read GetValue write SetValue;

您没有显示该属性的getter,但它必须返回一个副本,因为TStringEval是一个记录,一个值类型。

解决此问题的一种方法是将TStringEval作为参考类型。那就是将它从一个记录转换为一个类。这是一个非常剧烈的变化,你可能不会理会。

另一个选择是分配给Value而不是调用方法:

Console.Variables['developer'].Value := NewValue;

这导致了我认为代码中的基本设计缺陷。您的值类型具有变异Self的方法。这是许多不同程序员多次犯下的设计错误。最近,在FireMonkey库中发现了一些最引人注目的实例,它们反复提交此错误。

在您的问题中,问题是如何使用值类型的方法来改变值的原因。如果你没有改变你的值类型的方法,那么你就不会陷入这个陷阱。所以,我建议您删除所有SetValue方法,并用返回新值的静态类函数替换它们:

class function New(const S: string): TStringEval; static; overload;

然后修改值的唯一方法是这样:

Console.Variables['developer'].Value := TStringEval.New(...);

实际上,您甚至可以使用隐式强制转换运算符来使语法更加省事。