如何使用 TObjectList<T> 的 Contains、Remove 或 IndexOf 等方法
How to use methods like Contains, Remove or IndexOf of TObjectList<T>
我在使用 Contains
、Remove
或 IndexOf
之类的方法时遇到问题 TObjectList<T>
class,
当 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
和 Remove
使用 TMyObject
的 Equals
过程并覆盖该过程的实现。因此,我将 Equals
的以下实现添加到我的 TSocket class:
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
returns false 但应该是 true,IndexOf
returns -1 但应该是 0 而 Remove
不会删除对象,但应将其删除。我预计这些方法会使用 TSocket
的 Equals
方法,但他们没有使用。阅读文档后,我发现 TObjectList
的构造函数可以通过 IComparer 的实现来调用。因此,我实现了一个 TEqualityComparer<TSocket>
以便使用我的 Equals
方法。
不幸的是 TObjectList
的构造函数不支持 IEqualityComparer
接口,而是使用 IComparer
接口。
问题:
在 Delphi 中使用自定义类型时,如何使用 TObjectList<T>
的 Contains
、Remove
或 IndexOf
等方法?
在其他编程语言(如 Java 或 C#)中,Equals
用于比较列表类型中的对象。 Delphi 使用什么机制来比较对象?
更新
感谢您提供全面的反馈。我已经适当地更新了我的问题和代码。我详细阐述了 运行 代码时我的期望,并添加了更多代码以使我的意图更加清晰。
@DavidHeffernan:实施确实是错误的。我将继承添加到 TInterfacedObject 以了解有关引用计数的更多信息。我从代码中删除了 TInterfacedObject。
您的错误是您假设 TObjectList<T>
使用 Equals
函数来测试相等性。
默认情况下,TObjectList<T>
,或更准确地说 TList<T>
,使用由 TComparer<T>.Default
编辑的比较器 return。在 TObjectList<TSocket>
的情况下,默认比较器比较指针本身。由于您创建了 2 个不同的对象,因此指针不同。您得到的结果是预期的结果。
如果您想覆盖该默认行为,您需要提供自己的比较器。这样做的方法是像这样通过构造函数传递它:
TObjectList<TSocket>.Create(TComparer<TSocket>.Construct(
function (const L, R : TSocket) : Integer
begin
//Compare here.
end)
);
您的函数应该:
- Return 如果 L 小于 R,则该值小于 0。(通常为 -1)
- Return 如果 L 大于 R,则值大于 0。(通常为 1)
- Return 0个都相等
如果出于某种原因,您只想检查是否相等,从技术上讲,您可以这样做,如果不相等,则 return 为 -1 或 1,无需进一步比较。也就是说,只要您不打算通过它对列表或 BinarySearch 进行排序。
我在使用 Contains
、Remove
或 IndexOf
之类的方法时遇到问题 TObjectList<T>
class,
当 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
和 Remove
使用 TMyObject
的 Equals
过程并覆盖该过程的实现。因此,我将 Equals
的以下实现添加到我的 TSocket class:
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
returns false 但应该是 true,IndexOf
returns -1 但应该是 0 而 Remove
不会删除对象,但应将其删除。我预计这些方法会使用 TSocket
的 Equals
方法,但他们没有使用。阅读文档后,我发现 TObjectList
的构造函数可以通过 IComparer 的实现来调用。因此,我实现了一个 TEqualityComparer<TSocket>
以便使用我的 Equals
方法。
不幸的是 TObjectList
的构造函数不支持 IEqualityComparer
接口,而是使用 IComparer
接口。
问题:
在 Delphi 中使用自定义类型时,如何使用 TObjectList<T>
的 Contains
、Remove
或 IndexOf
等方法?
在其他编程语言(如 Java 或 C#)中,Equals
用于比较列表类型中的对象。 Delphi 使用什么机制来比较对象?
更新 感谢您提供全面的反馈。我已经适当地更新了我的问题和代码。我详细阐述了 运行 代码时我的期望,并添加了更多代码以使我的意图更加清晰。 @DavidHeffernan:实施确实是错误的。我将继承添加到 TInterfacedObject 以了解有关引用计数的更多信息。我从代码中删除了 TInterfacedObject。
您的错误是您假设 TObjectList<T>
使用 Equals
函数来测试相等性。
默认情况下,TObjectList<T>
,或更准确地说 TList<T>
,使用由 TComparer<T>.Default
编辑的比较器 return。在 TObjectList<TSocket>
的情况下,默认比较器比较指针本身。由于您创建了 2 个不同的对象,因此指针不同。您得到的结果是预期的结果。
如果您想覆盖该默认行为,您需要提供自己的比较器。这样做的方法是像这样通过构造函数传递它:
TObjectList<TSocket>.Create(TComparer<TSocket>.Construct(
function (const L, R : TSocket) : Integer
begin
//Compare here.
end)
);
您的函数应该:
- Return 如果 L 小于 R,则该值小于 0。(通常为 -1)
- Return 如果 L 大于 R,则值大于 0。(通常为 1)
- Return 0个都相等
如果出于某种原因,您只想检查是否相等,从技术上讲,您可以这样做,如果不相等,则 return 为 -1 或 1,无需进一步比较。也就是说,只要您不打算通过它对列表或 BinarySearch 进行排序。