2015-01-07 25 views
2

我有以下設置:會員沒有改變對轉讓

//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。我暫時想要將它設置的更高,以便在不重新編譯控制檯代碼的情況下從應用程序獲取更詳細的輸出(它位於程序包中)。

+0

難以檢查不能編譯的不完整代碼;可能你的代碼會將一個值賦給一個隱藏的臨時變量,而不是你需要的變量。 – kludg

+1

爲了記錄,代碼被放置在幾個單元中,分佈在應用程序和包中,您如何期望我展示它以便編譯它? – ZzZombo

+0

使SSCCE重現問題;當然不是一件難事。 – kludg

回答

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(...); 

事實上你甚至可以使用一個隱式的轉換操作符來使語法更加有用。

+0

呃,我甚至想過你的解決方案(創建一個返回新記錄的靜態方法),但放棄了它。我現在就試一試。謝謝。我懷疑你已經解釋了,但當時並不確定。現在這一切都有道理。 – ZzZombo