2016-06-04 5 views
2

TObjectList와 의 포함합니다 좋아합니다. 사용 방법 방법은 제거하거나 같이 IndexOf 나는 T는 다음 예제 코드 <code>TSocket</code> 같은 사용자 정의 유형 인 경우 <code>Contains</code>, <code>Remove</code> 또는 <code>TObjectList<T></code> 클래스의 <code>IndexOf</code>, 같은 방법을 사용하는 데 문제가

내가 정의 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, IndexOfTMyObjectEquals 절차의 Remove 메이크업 사용과 이 절차의 구현을 덮어 씁니다. , IndexOf true를 반환해야 Contains false를 반환하지만,이 코드를 사용하여

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; 

-1 만 0 Remove 개체를 제거하지 않고 그것을 제거해야해야한다 : 그러므로 나는 내 TSocket 클래스에 Equals의 다음 된 구현에 추가 . 나는이 방법들이 그들이하지 않은 TSocketEquals 방법을 사용할 것이라고 기대했다. 문서를 읽은 후에 나는 TObjectList의 생성자가 IComparer의 구현과 함께 호출 될 수 있다는 것을 알아 냈습니다. 따라서 내 Equals 메서드를 사용하기 위해 TEqualityComparer<TSocket>을 구현했습니다. 불행히도 TObjectList의 생성자는 IEqualityComparer 인터페이스를 지원하지 않지만 대신 IComparer 인터페이스를 사용합니다.

질문 : 어떻게 델파이에서 사용자 정의 형식을 사용할 때이 Contains, Remove 또는 TObjectList<T>IndexOf 같은 방법을 사용합니까? 다른 프로그래밍 언어 (예 : Java 또는 C#)에서는 목록 유형의 객체를 비교하는 데 Equals이 사용됩니다. Delphi는 객체를 비교하기 위해 어떤 메커니즘을 사용합니까?

업데이트 종합적인 의견을 보내 주셔서 감사합니다. 내 질문과 코드를 적절하게 업데이트했습니다. 코드를 실행할 때 내 기대가 무엇인지 정교하게하고 내 의도를 명확하게하기 위해 추가 코드를 추가했습니다. @DavidHeffernan : 구현이 잘못되었습니다. 참조 계산에 대해 더 자세히 알아보기 위해 TInterfacedObject에 상속을 추가했습니다. 코드에서 TInterfacedObject를 제거했습니다.

+0

큰 문제는 참조 계산 된 인터페이스와 개체를 혼합하는 것입니다. 너는 그걸 막아야 해. 여기 코드의 모든 부분은 잘못되었습니다. 'Contains','Remove','IndexOf'는 이미 타입으로 잘 작동하지만 잘못된 타입을 사용하고 있으므로 다시 시작해야합니다. –

+0

죄송합니다. 코드 품질이 좋지 않으면 언어를 배우려고합니다. – MUG4N

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

함수해야 :

  • 복귀 L은 R.보다 낮 으면 0보다 낮은 값 (통상적으로 -1)
  • L이 R보다 큰 경우 0보다 큰 값을 반환합니다. (일반적으로 1)
  • 둘 모두의 반환 0은 같음입니다.

어떤 이유로 든 동등성 만 검사하려는 경우 기술적으로 그렇게 할 수 있으며 더 이상 비교하지 않으면 동일하지 않을 때 -1 또는 1을 반환 할 수 있습니다. 즉, 목록을 정렬하거나 BinarySearch를 통해 정렬하지 않으려는 경우입니다.

+0

greate 답변 주셔서 감사합니다! 마지막 단락은 Equals가 목록 내의 객체를 비교하는 올바른 방법이 아닌 것처럼 들립니다. 그렇지 않으면 TEqualityComparer가 생성자 매개 변수로 허용됩니다. Equals 메서드를 사용하는 것이 잘못 되었습니까? 비교 자 구현에서 무엇을 확인하겠습니까? – MUG4N

+1

비교 자의 역할은 일반적으로 목록을 정렬하거나 목록을 정렬하는 것입니다. TEqualityComparer로는 정렬 할 수 없습니다. "정렬"기능이 필요하지 않으므로 비교자를 Equal (0)/Not Equal (0 이외)으로 반환하는 것이 "OK"입니다. 그들은 TComparer가 바로 그 다음에 할 수 있기 때문에 아마도 TEqualityComparer 매개 변수를 넣지 않았을 것입니다. –

+1

fwiw imho는'Contains','Remove' 및'IndexOf'의 구현이 의도적으로 깨졌습니다. 그들은'IComparer '을 사용 중이며'IEqualityComparer '이 아닙니다. 만약 그들이'IEqualityComparer '을 사용한다면 그들은 실제로 클래스의 T 타입에 대해'TObject'의 가상'Equals' 메쏘드를 사용할 것입니다 ('System.Generics.Defaults.Equals_Class'를보십시오). –