【发布时间】:2016-08-31 10:39:01
【问题描述】:
我正在创建一个 Datasnap 服务器和客户端集,最终用于连接(服务器)到几个不同的数据库。对于服务器,我创建了一个名为 TMember 的测试类。服务器和客户端使用这个单元(uMember)。
我在服务器上放置了一个函数,该函数创建一个 TMember 并将其返回给请求的客户端机器。 TMember 对象中的一些数据是从 SQL Server 数据库中收集的。
在客户端,我创建了一个 TObjectList 类型的全局变量(在我的客户端主窗体上)。每次我触发 Create New Member 函数时,对象都会在服务器上创建并成功发送回客户端。我可以访问对象的方法和属性。
然而,我的问题是遍历这个 TObjectList 集合。无论我采用哪种方式,我都只会获得 AV。这是我的代码尝试。谁能指出我在哪里搞砸了?
非常感谢您!
TMember界面如下:
type
TMember = class
FFirstName : String;
FLastName : String;
FFullname : String;
FAddress : String;
private
{private declarations}
public
{public declarations and properties}
constructor Create(fname, lname : String); overload;
constructor Create(otherMember : TMember); overload;
destructor Destroy;
procedure SetFName(const Value: String);
procedure SetFullname(const Value: String);
procedure SetLName(const Value: String);
function GetFullname : String;
function ToString : String;
procedure ChangeAddr(Addr : String);
property Name : String read FFirstName write SetFName;
property Surname : String read FLastName write SetLName;
property Fullname : String read GetFullname write SetFullname;
end;
此代码用于从服务器创建一个新的 TMember 对象:
procedure TfrmMainClient.btnCreateMemClick(Sender: TObject);
var
Server : TServerMethodsClient;
newMem : TMember;
i : Integer;
begin
try
Server := TServerMethodsClient.Create(DM1.ServerConn.DBXConnection);
newMem := Server.GetMember(edtFName.Text, '');
if Assigned(newMem) then begin
AllMembers.Add(newMem);
Listbox1.Items.Add(newMem.GetFullname);
end;
finally
Server.Free;
end;
end;
因此,一段时间后,客户端的内存中会出现几个对象。现在我想从列表框中访问它们(好像它是一个“菜单”来选择一个 TMember)。这个想法是/是记录列表框的 ItemIndex 并将其发送到 AllMember TObjectList 对象集合以访问位于该索引处的 TMember。这创造了一个可爱的小 AV。所以,然后我尝试使用基本的 for..do 循环对 ObjectList 进行简单的迭代,以填充 Listbox。结果相同。我也尝试了 for..in 循环,但无济于事。
我很确定我只是错过了一些愚蠢的事情......
这是尝试#1:
procedure TfrmMainClient.btnRefreshClick(Sender: TObject);
var
nextMember : TMember;
begin
for nextMember in AllMembers do
begin
Listbox1.Items.Add(nextMember.GetFullname);
end;
end;
这是尝试#2:
procedure TfrmMainClient.btnRefreshClick(Sender: TObject);
var
nextMember : TMember;
i : Integer;
begin
for i := 0 to AllMembers.Count - 1 do
begin
nextMEmber := TMember.Create(AllMembers[i]);
Listbox1.Items.Add(nextMember.GetFullname);
end;
end;
这是尝试#3:
procedure TfrmMainClient.btnRefreshClick(Sender: TObject);
var
nextMember : TMember;
i : Integer;
begin
for i := 0 to AllMembers.Count - 1 do
begin
nextMember := AllMembers.Items[i];
Listbox1.Items.Add(nextMember.GetFullname);
end;
end;
我相信有人可以提供帮助...
编辑 1:
改变这个
procedure TfrmMainClient.btnRefreshClick(Sender: TObject);
var
i: Integer;
Item : TPair<Integer, TMember>;
ActiveMember : TMember;
Key : Integer;
begin
Listbox1.Clear;
for i := 0 to AllMembersKeys.Count - 1 do
begin
try
ActiveMember := TMember.Create('','');
//Get the MemberID as a Key stored in AllMembersKeys
Key := AllMembersKeys[i];
//Now try get this TMember record from the AllMembers collection
if AllMembers.TryGetValue(Key, ActiveMember) then
if ActiveMember <> nil then
Listbox1.Items.Add(ActiveMember.GetFullname)
else
Listbox1.Items.Add('Could not locate TMember with Key: ' + IntToStr(Key));
finally
ActiveMember.Free;
end;
end;
end;
到
procedure TfrmMainClient.btnRefreshClick(Sender: TObject);
var
Key : Integer;
begin
Listbox1.Clear;
for Key in AllMembers.Keys do
begin
Listbox1.Items.Add(AllMembers[Key].GetFullname);
end;
end;
【问题讨论】:
-
旁白:构造函数必须在尝试之前出现,否则构造函数中的异常会导致您在未初始化的引用上调用
Free。 -
至于问题,有很多细节缺失。从
GetMember返回的对象。谁拥有它?谁负责摧毁它?AllMembers是什么?TObjectList与OwnsObjects设置为True。这听起来像是一个需要minimal reproducible example 的问题。 -
Server.GetMemeber()是如何实现的?正如@David 所说,请提供一个 MCVE。否则有太多的猜测。 -
调试你的程序。为您的类创建一个空的重写析构函数。在其上放置一个断点并运行您的代码。检查调用堆栈并查看析构函数何时以及由谁调用
标签: delphi datasnap delphi-10-seattle