我在使用==
类的if
,Contains
或Remove
等方法时遇到问题,
当T是以下示例代码中的IndexOf
之类的自定义类型时。
我开始实施自定义TObjectList<T>
类型,并尝试在TSocket
类型的列表中使用它,如下所示:
TSocket
我希望TObjectList<TSocket>
,list := nil;
socket := nil;
try
list := TObjectList<TSocket>.Create();
socket := TSocket.Create(TIpAddress.Parse('127.0.0.1'),6857);
// add new socket object with equal values to list
list.Add(TSocket.Create(TIpAddress.Parse('127.0.0.1'),6857));
// should return true but returns false
if list.Contains(socket) then
WriteLn('socket contained in list')
else
WriteLn('socket not contained in list');
// should return number 0 but returns -1
if list.IndexOf(socket) = 0 then
WriteLn('socket contained in list')
else
WriteLn('socket not contained in list');
// should remove item from list but items doesn't get removed
list.Remove(socket);
finally
list.Free();
socket.Free();
和Contains
使用IndexOf
的{{1}}过程,并覆盖此过程的实施。因此,我将Remove
的以下实现添加到我的TSocket类:
Equals
使用此代码TMyObject
返回false但应该为true,Equals
返回-1但应该为0而type
TSocket = class
strict private
_ipAddress: TIpAddress;
_port: integer;
public
constructor Create(ipAddress: TIpAddress; port: integer);
function GetIpAddress: TIpAddress;
function GetPort: integer;
property IpAddress: TIpAddress read GetIpAddress;
property Port: integer read GetPort;
function Equals(other: TObject): boolean; overload; override;
destructor Destroy; override;
end;
implementation
constructor TSocket.Create(ipAddress: TIpAddress; port: integer);
begin
inherited Create();
_ipAddress := ipAddress;
_port := port;
end;
function TSocket.Equals(other: TObject): boolean;
var
otherSocket: TSocket;
begin
if not (other is TSocket) then exit(false);
otherSocket := other as TSocket;
result:= (_ipAddress.Equals(otherSocket.IpAddress)) and (_port = otherSocket.Port)
end;
function TSocket.GetIpAddress: TIpAddress;
begin
result := _ipAddress;
end;
function TSocket.GetPort: integer;
begin
result := _port;
end;
destructor TSocket.Destroy;
begin
_ipAddress.Free();
inherited Destroy();
end;
不会删除对象但应将其删除。我希望这些方法可以使用他们没有的Contains
IndexOf
方法。在阅读文档后,我发现Remove
的构造函数可以通过IComparer的实现来调用。因此,我实施了Equals
以使用我的TSocket
方法。
不幸的是,TObjectList
的构造函数不支持TEqualityComparer<TSocket>
接口,而是使用Equals
接口。
问题:
在Delphi中使用自定义类型时,如何使用TObjectList
的{{1}},IEqualityComparer
或IComparer
等方法?
在其他编程语言(如Java或C#)中,Contains
用于比较列表类型中的对象。 Delphi使用什么机制来比较对象?
更新 感谢您提供全面的反馈。我已适当更新了我的问题和代码。我详细说明了在运行代码时我的期望是什么,并添加了更多代码以使我的意图更清晰。 @DavidHeffernan:实施确实是错误的。我将继承添加到TInterfacedObject以了解有关引用计数的更多信息。我从代码中删除了TInterfacedObject。
答案 0 :(得分:7)
您的错误是您假设TObjectList<T>
使用Equals
函数来测试相等性。
默认情况下,TObjectList<T>
或更准确TList<T>
使用TComparer<T>.Default
返回的比较器。在TObjectList<TSocket>
的情况下,默认比较器比较指针本身。由于您创建了2个不同的对象,因此指针不同。得到的结果是预期的结果。
如果要覆盖该默认行为,则需要提供自己的比较器。这样做的方法是将它传递给构造函数,如下所示:
TObjectList<TSocket>.Create(TComparer<TSocket>.Construct(
function (const L, R : TSocket) : Integer
begin
//Compare here.
end)
);
你的功能应该:
如果出于某种原因,你只想检查是否相等,那么你可以在技术上这样做,如果它不相等则返回-1或1而不进一步比较。也就是说,只要您不打算通过它对列表或BinarySearch进行排序。