这个问题以前可能已经问过很多次了,但如果是这样的话,我一辈子也找不到答案,所以如果是这样的话,我提前道歉。
我在一个 Delphi 单元中有一个对象,我正在整理来自一个源的TEmployerData
类型的雇主列表,如下所示。
一旦我整理了一份雇主名单,我将从其他来源收集属于每个雇主的雇员和工资单数据。
unit EmployerObjUnit;
interface
uses
Classes, SysUtils, Variants,Types, Generics.Collections, Generics.Defaults, EmployeeObjUnit, PayObjUnit;
type
TEmployerData = class
private
FErID: string;
FErName: string;
FErAccsRef: string;
FErPAYE: string;
FErAddr1: string;
FErAddr2: string;
FErAddr3: string;
FErAddr4: string;
FErPostCd: string;
FErPath: string;
FErEesList: TObjectList<TFPSEmployee>;
FErPayList: TObjectList<TFPSPayment>;
FErYears: TStringList;
procedure SetErID (const Value: string);
procedure SetErName (const Value: string);
procedure SetErAccsRef (const Value: string);
procedure SetErPAYE (const Value: string);
procedure SetErAddr1 (const Value: string);
procedure SetErAddr2 (const Value: string);
procedure SetErAddr3 (const Value: string);
procedure SetErAddr4 (const Value: string);
procedure SetErPostCd (const Value: string);
procedure SetErPath (const Value: string);
constructor Create; overload;
published
property ErID:string read FErID write SetErID;
property ErName:string read FErName write SetErName;
property ErAccsRef:string read FErAccsRef write SetErAccsRef;
property ErPAYE:string read FErPAYE write SetErPAYE;
property ErAddr1:string read FErAddr1 write SetErAddr1;
property ErAddr2:string read FErAddr2 write SetErAddr2;
property ErAddr3:string read FErAddr3 write SetErAddr3;
property ErAddr4:string read FErAddr4 write SetErAddr4;
property ErPostCd:string read FErPostCd write SetErPostCd;
property ErPath: string read FErPath write SetErPath;
property ErEesList: TObjectList<TFPSEmployee> read FErEesList;
property ErPayList: TObjectList<TFPSPayment> read FErPayList;
property ErYears: TStringList read FErYears;
public
procedure AddEmployee(const FPSEmployee: TFPSEmployee);
procedure AddPayslip(const FPSPayslip: TFPSPayment);
procedure AddYear(const Year: string);
end;
到目前为止一切顺利。
我想将雇员和工资单数据存储在ErEEsList
和ErPayList
ObjectList中,并将与这些数据相关的年份存储在ErYears
StringList中。
类代码的其余部分为:
constructor TEmployerData.Create;
begin
inherited;
FErEesList:=TObjectList<TFPSEmployee>.Create(True);
FErPayList:=TObjectList<TFPSPayment>.Create(True);
FErYears:=TStringList.Create;
end;
procedure TEmployerData.SetErAccsRef(const Value: string);
begin
// all the other setters are in here
end;
procedure TEmployerData.AddEmployee(const FPSEmployee: TFPSEmployee);
var
IsDupe: Boolean;
i: integer;
begin
if FErEesList.Count=0 then
FErEesList.Add(FPSEmployee)
else
begin
IsDupe:=False;
for i := 0 to FErEesList.Count-1 do
begin
if (FErEesList[i].PayID=FPSEmployee.PayID)
AND (FErEesList[i].AccountsRef=FPSEmployee.AccountsRef)
AND (FErEesList[i].TaxYear=FPSEmployee.TaxYear) then
IsDupe:=True;
end;
if IsDupe=False then
FErEesList.Add(FPSEmployee);
if IsDupe=True then
FPSEmployee.Free;
end;
FErEesList.Sort(TComparer<TFPSEmployee>.Construct(
function(const A, B :TFPSEmployee): integer
begin
if A.TaxYear=B.TaxYear then
Result:=0
else if A.TaxYear<B.TaxYear then
Result:=-1
else
Result:=1;
end
));
end;
procedure TEmployerData.AddPayslip(const FPSPayslip: TFPSPayment);
begin
FErPayList.Add(FPSPayslip);
FErPayList.Sort(TComparer<TFPSPayment>.Construct(
function(const A, B :TFPSPayment): integer
begin
if A.TaxYear=B.TaxYear then
Result:=0
else if A.TaxYear<B.TaxYear then
Result:=-1
else
Result:=1;
end
));
end;
procedure TEmployerData.AddYear(const Year: string);
var
i: integer;
GotYr: Boolean;
begin
GotYr:=False;
if FErYears.Count=0 then
FErYears.Add(Year)
else
begin
for i := 0 to FErYears.Count-1 do
begin
if Year=FErYears[i] then
GotYr:=True;
end;
if GotYr=False then
FErYears.Add(Year);
end;
end;
end.
现在,我可以毫无问题地整理我的雇主列表了。我可以得到我需要的每个雇员和工资单的信息,但是当我试图用AddEmployee()
或AddYear()
写任何东西时,我总是得到访问违规错误(甚至还没有到AddPayslip()
!)。不幸的是,我不够流利,无法找出原因。
上述类用于一个Form单元。ErsObjList: TObjectList<TEmployerData>;
以上声明在表单单元的Private
节中,创建表单时创建,关闭表单时释放。
然后用它来填充ErsObjList
。
procedure TGetXMLForm.Button1Click(Sender: TObject);
var
//more XML variables
ANode, BNode, CNode: IXMLNode;
NumDir: string;
Employer: TEmployerData;
begin
ErStream:=TFileStream.Create('Employer List.xml', fmOpenRead);
// load of xml setup
try
if Length(XList)>0 then
begin
for i := 0 to Length(XList)-1 do
begin
SetLength(FPSList, 0);
FPSList:=TDirectory.GetFiles(XList[i], 'FPS*.xml', TSearchOption.soAllDirectories);
try
if Length(FPSList)>0 then
begin
// scan through ErListXML for the corresponding number
ErNodes:=ErListXML.DocumentElement.ChildNodes;
if ErNodes.Count>0 then
begin
for x:= 0 to Ernodes.Count-1 do
begin
ANode:=ErNodes[x].ChildNodes.FindNode('Number');
if StrToInt(ANode.Text)=StrToInt(NumDir) then
begin
// create an employer obj from ErListXML
Employer:=TEmployerData.Create;
Employer.ErID:=ANode.Text;
Employer.ErName:=ErNodes[x].ChildNodes.FindNode('Name').Text;
// and so on until
Employer.ErPath:=XList[i];
ErsObjList.Add(Employer);
end;
end;
end;
end;
except
ShowMessage('Exception class name :- '+E.ClassName);
Exit;
end;
end;
end;
ErListXML.Free;
except
ShowMessage('Error reading Employer List xml file');
end;
end;
Button 1从一个源获取我的雇主数据,并构建一个ObjectList(ErsObjList
),没有出现任何问题。
然后,当单击Button2
时,我将使用以下命令:
procedure TGetXMLForm.Button2Click(Sender: TObject);
var
i: integer;
FPSStream: TStream;
begin
for i := 0 to ErsObjList.Count-1 do
begin
GetPayDetails(ErsObjList[i]);
WriteData;
end;
end;
这反过来又触发了一个更完整的版本(为了可读性,我只是删除了一些基本代码--没有任何会影响这个问题的代码):
procedure TGetXMLForm.GetRTIDetails(const Employer: TEmployerData);
var
FpsList: TStringDynArray;
// other items
TaxYear: string;
Employee: TFPSEmployee;
Payslip: TFPSPayment;
DateConInf: TFormatSettings;
TaxCd: string;
begin
SetLength(FpsList, 0);
FpsList:=TDirectory.GetFiles(Employer.ErPath, 'FPS*.xml', TSearchOption.soAllDirectories);
if Length(FpsList)>0 then
begin
try
for i := 0 to Length(FpsList)-1 do
begin
// loading some data from XML files
TaxYear:=CNode.ChildNodes.FindNode('RelatedYear').Text;
Employer.AddYear(TaxYear);
// my code then triggers an AV in the "AddYear" procedure
这就是出错的地方。它确实用正确的TaxYear
值调用了过程AddYear()
。它没有标记任何编译错误。我将感谢任何帮助。
- 已编辑 *
1条答案
按热度按时间jyztefdp1#
对于我尝试循环的所有代码,答案应该是非常明显的。但是正如我所说的,我没有足够的经验来知道。
TEmployerData
类constructor
声明在错误的位置,所以这些在创建
Employer
对象时未正确初始化。这会导致运行时AV。