Why is TList.Remove() producing an EAccessViolation error?

家住魔仙堡 提交于 2019-12-05 20:48:37

问题


Why EAccessViolation is raised when executing the code below?

uses
  Generics.Collections;
  ...

var
  list: TList<TNotifyEvent>;
  ...

begin
  list := TList<TNotifyEvent>.Create();
  try
    list.Add(myNotifyEvent);
    list.Remove(myNotifyEvent);  // EAccessViolation at address...
  finally
    FreeAndNil(list);
  end;
end;

procedure myNotifyEvent(Sender: TObject);
begin
  OutputDebugString('event');  // nebo cokoliv jineho
end;

回答1:


It looks like a bug.

If you compile with debug dcu's (normally don't do that unless you want to loose your sanity!) you see that a call to the comparer went wrong. A (possibly optional) third value of a compare function is not set and causes the access violation.

So possibly you can't put method pointers in a generic list.

Ok the following works:

uses
  Generics.Defaults;

type
  TForm4 = class(TForm)
    ...
  private
    procedure myNotifyEvent(Sender: TObject);
  end;

TComparer<T> = class (TInterfacedObject, IComparer<T>)
public
  function Compare(const Left, Right: T): Integer;
end;

implementation

uses
  Generics.Collections;

var
  list: TList<TNotifyEvent>;
begin
  list := TList<TNotifyEvent>.Create(TComparer<TNotifyEvent>.Create);
  try
    list.Add(myNotifyEvent);
    list.Remove(myNotifyEvent);
  finally
    FreeAndNil(list);
  end;
end;

procedure TForm4.myNotifyEvent(Sender: TObject);
begin
  ShowMessage('event');
end;

{ TComparer<T> }

function TComparer<T>.Compare(const Left, Right: T): Integer;
begin
  Result := 0;
end;

You have to define your own comparer, with possiby some more intelligence ;-).




回答2:


Access Violation is caused by missing comparer. I suspect this was fixed in a patch but the problem still persists (at least in Delphi 2009) if you use a TObjectList so I'm just updating with the simplest solution:

TList<TNotifyEvent>.Create(TComparer<TNotifyEvent>.Default);

or in my case

TObjectList<TNotifyEvent>.Create(TComparer<TNotifyEvent>.Default);



回答3:


Is it possible to pass a custom comparer to TList<T>? I don't have D2009 in front of me, so can't try it.




回答4:


the above code is used in TForm1 ...

uses 
  Generics.Collections;

procedure TForm1.Button1Click(Sender: TObject);
var
  list: TList<TNotifyEvent>;
begin
  list := TList<TNotifyEvent>.Create();
  try
    list.Add(myNotifyEvent);
    list.Remove(myNotifyEvent);  // EAccessViolation at address...
  finally
    FreeAndNil(list);
  end;
end;
procedure TForm1.myNotifyEvent(Sender: TObject);
begin
  OutputDebugString('event');  // nebo cokoliv jineho
end;


来源:https://stackoverflow.com/questions/289825/why-is-tlist-remove-producing-an-eaccessviolation-error

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!