课程成员的任务不会更改

ZzZ*_*mbo 2 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);
...
Run Code Online (Sandbox Code Playgroud)

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

Dav*_*nan 5

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

Console.Variables['developer'].Value.SetValue(MESSAGELEVEL_VERBOSE);
Run Code Online (Sandbox Code Playgroud)

这是尝试进行修改的代码.该属性TStringEval由该Value属性产生:

property Value: TStringEval read GetValue write SetValue;
Run Code Online (Sandbox Code Playgroud)

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

解决问题的一种方法是使其TStringEval成为引用类型.那就是将它从一个记录转换为一个类.这是一个非常剧烈的变化,你可能不会接受.

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

Console.Variables['developer'].Value := NewValue;
Run Code Online (Sandbox Code Playgroud)

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

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

class function New(const S: string): TStringEval; static; overload;
Run Code Online (Sandbox Code Playgroud)

那么修改值的唯一方法是这样的:

Console.Variables['developer'].Value := TStringEval.New(...);
Run Code Online (Sandbox Code Playgroud)

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