Delphi中如何高效实现从TList<class>到TList<interface>的转换?
高效实现Delphi中TList到接口列表的转换
针对你遇到的TList
方案1:只读包装类(零复制,最高效)
核心思路是实现一个包装类,直接映射原TObjectList
包装类实现
unit InterfaceListWrapper; interface uses Generics.Collections, Generics.Defaults; type TInterfaceListWrapper<T: class; I> = class(TInterfacedObject, IList<I>) strict private FInnerList: TObjectList<T>; public constructor Create(InnerList: TObjectList<T>); function GetCount: Integer; function GetItem(Index: Integer): I; procedure SetItem(Index: Integer; const Value: I); function Add(const Value: I): Integer; procedure Clear; function Contains(const Value: I): Boolean; function IndexOf(const Value: I): Integer; procedure Insert(Index: Integer; const Value: I); procedure Remove(const Value: I); procedure Delete(Index: Integer); function GetEnumerator: TEnumerator<I>; property Count: Integer read GetCount; property Items[Index: Integer]: I read GetItem write SetItem; default; end; implementation uses SysUtils; { TInterfaceListWrapper<T, I> } constructor TInterfaceListWrapper<T, I>.Create(InnerList: TObjectList<T>); begin inherited Create; FInnerList := InnerList; end; function TInterfaceListWrapper<T, I>.GetCount: Integer; begin Result := FInnerList.Count; end; function TInterfaceListWrapper<T, I>.GetItem(Index: Integer): I; begin Result := FInnerList[Index] as I; end; procedure TInterfaceListWrapper<T, I>.SetItem(Index: Integer; const Value: I); begin raise ENotSupportedException.Create('列表为只读'); end; function TInterfaceListWrapper<T, I>.Add(const Value: I): Integer; begin raise ENotSupportedException.Create('列表为只读'); end; procedure TInterfaceListWrapper<T, I>.Clear; begin raise ENotSupportedException.Create('列表为只读'); end; function TInterfaceListWrapper<T, I>.Contains(const Value: I): Boolean; begin if Value is T then Result := FInnerList.Contains(Value as T) else Result := False; end; function TInterfaceListWrapper<T, I>.IndexOf(const Value: I): Integer; begin if Value is T then Result := FInnerList.IndexOf(Value as T) else Result := -1; end; procedure TInterfaceListWrapper<T, I>.Insert(Index: Integer; const Value: I); begin raise ENotSupportedException.Create('列表为只读'); end; procedure TInterfaceListWrapper<T, I>.Remove(const Value: I); begin raise ENotSupportedException.Create('列表为只读'); end; procedure TInterfaceListWrapper<T, I>.Delete(Index: Integer); begin raise ENotSupportedException.Create('列表为只读'); end; function TInterfaceListWrapper<T, I>.GetEnumerator: TEnumerator<I>; type TInterfaceEnumerator = class(TEnumerator<I>) strict private FInnerEnum: TEnumerator<T>; protected function DoGetCurrent: I; override; function DoMoveNext: Boolean; override; public constructor Create(InnerEnum: TEnumerator<T>); destructor Destroy; override; end; begin Result := TInterfaceEnumerator.Create(FInnerList.GetEnumerator); end; { TInterfaceEnumerator } constructor TInterfaceListWrapper<T, I>.TInterfaceEnumerator.Create(InnerEnum: TEnumerator<T>); begin inherited Create; FInnerEnum := InnerEnum; end; destructor TInterfaceListWrapper<T, I>.TInterfaceEnumerator.Destroy; begin FInnerEnum.Free; inherited; end; function TInterfaceListWrapper<T, I>.TInterfaceEnumerator.DoGetCurrent: I; begin Result := FInnerEnum.Current as I; end; function TInterfaceListWrapper<T, I>.TInterfaceEnumerator.DoMoveNext: Boolean; begin Result := FInnerEnum.MoveNext; end; end.
修改原类的GetChucks方法
unit Unit11; interface uses Generics.Collections, InterfaceListWrapper; type IChuck = interface end; TChuck = class(TInterfacedObject, IChuck) end; TProgram = class strict private FChucks: TObjectList<TChuck>; private function GetChucks: IList<IChuck>; public constructor Create; destructor Destroy; override; property Chucks: IList<IChuck> read GetChucks; end; implementation uses SysUtils; { TProgram } constructor TProgram.Create; begin FChucks := TObjectList<TChuck>.Create; end; destructor TProgram.Destroy; begin FreeAndNil(FChucks); inherited; end; function TProgram.GetChucks: IList<IChuck>; begin // 返回包装类实例,无元素复制 Result := TInterfaceListWrapper<TChuck, IChuck>.Create(FChucks); end; end.
方案2:延迟缓存+失效机制(读多写少场景)
如果需要外部可修改接口列表,或者必须返回TList
修改原类实现
unit Unit11; interface uses Generics.Collections; type IChuck = interface end; TChuck = class(TInterfacedObject, IChuck) end; TProgram = class strict private FChucks: TObjectList<TChuck>; FChucksCache: TList<IChuck>; FCacheValid: Boolean; procedure InvalidateCache; private function GetChucks: TList<IChuck>; public constructor Create; destructor Destroy; override; procedure AddChuck(AChuck: TChuck); procedure RemoveChuck(AChuck: TChuck); procedure ClearChucks; property Chucks: TList<IChuck> read GetChucks; end; implementation uses SysUtils; { TProgram } constructor TProgram.Create; begin FChucks := TObjectList<TChuck>.Create; FChucksCache := TList<IChuck>.Create; FCacheValid := False; end; destructor TProgram.Destroy; begin FChucksCache.Free; FChucks.Free; inherited; end; procedure TProgram.InvalidateCache; begin FCacheValid := False; end; procedure TProgram.AddChuck(AChuck: TChuck); begin FChucks.Add(AChuck); InvalidateCache; end; procedure TProgram.RemoveChuck(AChuck: TChuck); begin FChucks.Remove(AChuck); InvalidateCache; end; procedure TProgram.ClearChucks; begin FChucks.Clear; InvalidateCache; end; function TProgram.GetChucks: TList<IChuck>; var LChuck: TChuck; begin if not FCacheValid then begin FChucksCache.Clear; for LChuck in FChucks do FChucksCache.Add(LChuck); FCacheValid := True; end; Result := FChucksCache; end; end.
方案3:直接存储接口列表(代码最简)
如果业务允许,可以直接将内部存储改为TList
简化实现
unit Unit11; interface uses Generics.Collections; type IChuck = interface end; TChuck = class(TInterfacedObject, IChuck) end; TProgram = class strict private FChucks: TList<IChuck>; private function GetChucks: TList<IChuck>; public constructor Create; destructor Destroy; override; procedure AddChuck(AChuck: TChuck); property Chucks: TList<IChuck> read GetChucks; end; implementation uses SysUtils; { TProgram } constructor TProgram.Create; begin FChucks := TList<IChuck>.Create; end; destructor TProgram.Destroy; begin FChucks.Free; inherited; end; procedure TProgram.AddChuck(AChuck: TChuck); begin FChucks.Add(AChuck); // 自动转换为IChuck接口 end; function TProgram.GetChucks: TList<IChuck>; begin Result := FChucks; end; end.
方案对比
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 只读包装类 | 零复制、性能最高、数据安全 | 仅支持只读操作 | 外部只需读取数据的场景 |
| 延迟缓存+失效机制 | 读操作高效、支持修改 | 需要维护缓存失效逻辑 | 读多写少的业务场景 |
| 直接存储接口列表 | 代码最简、无转换开销 | 需处理引用计数生命周期 | 接口生命周期易管理的场景 |
内容的提问来源于stack exchange,提问作者Kirito
相关产品推荐
相关产品推荐

