2

当 T 是以下示例代码中的自定义类型时,我在使用类似 或 类Contains的方法时遇到Remove问题IndexOfTObjectList<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();

我期望ContainsIndexOfRemove利用该Equals程序的程序TMyObject并覆盖该程序的执行。Equals因此,我在我的 TSocket 类中添加了以下实现:

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返回 false 但应为 true,IndexOf返回 -1 但应为 0 并且Remove不删除对象但应删除它。我希望这些方法会使用他们没有使用的Equals方法。TSocket阅读文档后,我发现TObjectList可以使用 IComparer 的实现来调用构造函数。因此我实现了一个TEqualityComparer<TSocket>为了使用我的Equals方法。不幸的是,构造函数TObjectList不支持IEqualityComparer接口,而是使用IComparer接口。

问题:在 Delphi 中使用自定义类型时 如何使用Contains,RemoveIndexOfof 之类的方法?TObjectList<T>在其他编程语言(如 Java 或 C#)Equals中,用于比较列表类型中的对象。Delphi 使用什么机制来比较对象?

更新 感谢您的全面反馈。我已经适当地更新了我的问题和代码。我详细说明了我在运行代码时的期望,并添加了更多代码以使我的意图更加清晰。@DavidHeffernan:实施确实是错误的。我向 TInterfacedObject 添加了继承,以了解有关引用计数的更多信息。我从代码中删除了 TInterfacedObject。

4

1 回答 1

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

您的功能应该:

  • 如果 L 小于 R,则返回小于 0 的值。(通常为 -1)
  • 如果 L 大于 R,则返回大于 0 的值。(通常为 1)
  • 两者的返回 0 是相等的。

如果出于某种原因,您只想检查是否相等,则从技术上讲,您可以这样做,并在不相等时返回 -1 或 1 而无需进一步比较。也就是说,只要您不打算通过它对列表或 BinarySearch 进行排序。

于 2016-06-05T16:39:42.277 回答