如何使用接口返回对象列表?

时间:2017-01-05 16:40:17

标签: delphi

我有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不兼容的类型:   'System.Generics.Collections.TList <IInterfaceA>'和   'System.Generics.Collections.TObjectList <TClassB>'

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

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

我该如何解决?

1 个答案:

答案 0 :(得分:4)

从错误信息中可以明显看出问题是什么。 Manager.Find<TClassA>.List正在返回TObjectList<TClassB>(为什么TClassB而不是TClassA?),这与TList<IInterfaceA>的类型不同,因此无法返回 - 是

要使代码编译,您需要更像这样的东西:

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;

然而,这引入了两个问题:

  1. Result的内存管理。由于返回的TList<IInterfaceA>不归任何人所有,因此调用者在使用它时必须手动Free。如果Manager拥有Find()返回的列表,则原始代码中的情况不是这样。如果没有,那么您的原始代码就会遇到这个问题。

  2. 列表中对象的内存管理。由于对象是由TInterfacedObject引用计数的,因此当它们的IInterfaceA接口添加到返回的TList<IInterfaceA>时,它们的引用计数将递增,然后在从列表中删除它们时递减。由于Manager.Find()返回的原始列表包含TClassA个对象指针而不是IInterfaceA接口指针,因此无法正确管理对象的引用计数。释放/清除TList<IInterfaceA>后,您的对象可能会过早释放(除非您将TClassA指针添加到Manager列表时手动增加其引用计数,并且删除指针时手动递减它们。)

  3. 否则,您需要更改Manager.Find()以返回TList<IInterfaceA>而不是TObjectList<TClassB>

    您应该考虑重新考虑您的Manager设计。混合对象指针和接口对象的接口指针是不好的设计。处理接口对象时,应该使用接口来处理所有事情。否则,为避免出现问题,您的实现类需要覆盖_AddRef()_Release()方法以禁用引用计数。