2017-01-05 1 views
1

I가 2 개 인터페이스 ..인터페이스를 사용하여 객체 목록을 반환하는 방법은 무엇입니까?

IInterfaceA = interface 
    ..... 
End; 

IInterfaceB = interface 
['{834D7063-AE8F-40BF-B1E7-E0806EB991C7}'] 
    Function getA (A: Integer): IInterfaceA; 
  Function getList: TList <IInterfaceA>; 
End; 

TClassA = class (TInterfacedObject, IInterfaceA) 
    .... 
End 

TClassB = class (TInterfacedObject, IInterfaceB) 
  Function getA (A: Integer): IInterfaceA; 
  Function getList: TList <IInterfaceA>; 
End; 

// It works 
Function TClassB.getA (A: Integer): IInterfaceA; 
Begin 
  Result: = Manager.Find <TClassA> .Add (Linq.Eq ('fieldxxx', A.ToString).) UniqueResult; 
End; 

이 작동하지 않음 다음이 오류 발생 :

E2010 Incompatible types: 'System.Generics.Collections.TList <IInterfaceA>' and 'System.Generics.Collections.TObjectList <TClassB>'

Function TClassB.getList: TList <IInterfaceA>; 
Begin 
  // The TClassA class implements the interface IInterfaceA 

  Result: = Manager.Find <TClassA> .List; 
End; 

내가 어떻게 해결합니까를?

+0

코드가 충분하지 않습니다. 우리는 MCVE를 가질 수 없습니까? 오류 메시지가 분명해 보입니다. 그것이 무엇을 말하고 있는지 이해하십니까? –

+0

충분한 코드가 보이지 않습니다. 'Manager.Find'는 어떤 타입을 반환합니까? –

+2

오류 메시지는 유형이 무엇인지 알려줍니다. 오류 메시지는 정말 분명합니다. 때때로 사람들은 그것을 읽지 않습니다. –

답변

4

오류 메시지에서 문제가 무엇인지 분명합니다. Manager.Find<TClassA>.ListTObjectList<TClassB> (TClassB이 아닌 이유는 TClassA?)이며, TList<IInterfaceA>과 동일한 유형이 아니므로 반환되므로 현재 상태로 반환 될 수 없습니다.

은 더 이런 식으로 뭔가를 필요 코드 를 컴파일 할 수 있도록하려면 다음 Result

  1. 메모리 관리 :

    Function TClassB.getList: TList<IInterfaceA>; 
    var 
        Obj: TClassA; 
    begin 
        // The TClassA class implements the interface IInterfaceA 
        Result := TList<IInterfaceA>.Create; 
        try 
        for Obj in Manager.Find<TClassA>.List do 
         Result.Add(Obj as IInterfaceA); 
        except 
        Result.Free; 
        raise; 
        end; 
    end; 
    

    그러나,이 두 가지 문제를 소개합니다. 반환 된 TList<IInterfaceA>은 누구에게도 소유되어 있지 않으므로 발신자가 사용하면 수동으로 Free을 입력해야합니다. 원래 코드에서 ManagerFind()이 반환하는 목록을 소유하고있는 경우에는 해당되지 않습니다. 그렇지 않으면 원래 코드가이 문제로 시작됩니다.

  2. 목록에있는 개체의 메모리 관리. 객체는 TInterfacedObject으로 인해 참조 카운트되므로 참조 카운트는 IInterfaceA 인터페이스가 반환 된 TList<IInterfaceA>에 추가되고 목록에서 제거되면 감소됩니다. Manager.Find()에 의해 반환 된 원래 목록에는 TClassA 개체 포인터가 포함되어 있고 IInterfaceA 인터페이스 포인터는 포함되어 있지 않으므로 개체의 참조 횟수가 올바르게 관리되지 않습니다. TList<IInterfaceA>이 해제되거나 해제되면 Manager의 포인터에 TClassA 포인터를 추가 할 때 수동으로 참조 횟수를 늘리고 포인터를 제거 할 때 수동으로 감소시키지 않으면 개체가 너무 빨리 해제 될 수 있습니다.

그렇지 않으면, 당신은 대신 TObjectList<TClassB>TList<IInterfaceA>을 반환 Manager.Find()을 변경해야합니다.

어쨌든 Manager 디자인을 다시 생각해보십시오. 객체 포인터와 인터페이스 포인터를 인터페이스 객체에 혼합하는 것은 나쁜 설계입니다. 인터페이스 된 객체를 다룰 때는 모든 것을 위해 인터페이스를 사용해야합니다. 그렇지 않으면 문제를 피하기 위해 구현 클래스는 _AddRef()_Release() 메소드를 재정 의하여 참조 계산을 비활성화해야합니다.

+0

엄밀히 말하면 구현이 아무 것도하지 않더라도'_AddRef()'와'_Release()'가 여전히 호출되기 때문에 "참조 카운팅을 비활성화"할 수 없습니다. 따라서 여전히 객체 참조를 통해 기본 인스턴스를 파기하지 않도록주의해야합니다. 인터페이스 참조는 여전히 객체 참조를 가리 킵니다. 기본 인스턴스를 가리키는 각 객체 참조에 대해 추가로'_AddRef()'및'_Release()'호출을 수동으로 수행하는 것이 더 안전하다고 생각합니다. (어느 쪽이든 그것은 기름과 물을 섞어 놓는 것과 같습니다.) –

+0

@Craig : 수동으로 호출하는 이유는 무엇입니까? 참조가 nil인지 확인하십시오. –

+1

@Rudy 우리가 똑같은 페이지에 있다는 것을 분명히하기 위해서 ... 레미는 당신이 *** 객체와 인터페이스 참조를 섞어 놓고 있다면주의 사항을 설명하고 있었습니까? 어떤 경우에 당신은 객체 참조가 ** 없다는 것을 ** ** 설정/nilling 객체 참조 _는 자동으로'AddRef()/Release()'를 호출하지 않습니다. 두 가지 시나리오가 바람직하지 않을 수 있습니다. (1) 인터페이스 참조가 여전히 존재하는 동안 객체 참조를 통해 객체를 삭제합니다. (2) 객체 참조가 여전히 존재하는 동안 모든 인터페이스의 참조 및 파괴 객체를 초기화합니다. ... 쉬운 해결책 : 객체 참조를 위해 refcount를 수동으로 업데이트하십시오. –

관련 문제