首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >带泛型的Delphi TDictionary

带泛型的Delphi TDictionary
EN

Stack Overflow用户
提问于 2019-09-16 19:31:54
回答 2查看 343关注 0票数 0

我需要一个由字符串索引的不同TProc的容器。就像TDictionary一样。

代码语言:javascript
复制
TMessageBus = class
    private
        fContainer: TDictionary<String, TProc<T>>;  // ERROR !!
    public
        procedure Send<T>(aName: String; aData: T); // producer
        procedure Subscribe<T>(aName: String; aProc: TProc<T>); // consumer
end;

请帮帮忙。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-09-16 23:09:08

知道TProc<T>是作为接口实现的,您可以编写以下代码:

代码语言:javascript
复制
type
  TMessageBus = class
  private
    fContainer: TDictionary<string, IInterface>;
  public
    constructor Create;
    destructor Destroy; override;
    procedure Send<T>(const aName: string; const aData: T);
    procedure Subscribe<T>(const aName: string; const aProc: TProc<T>);
  end;

constructor TMessageBus.Create;
begin
  fContainer := TDictionary<string, IInterface>.Create;
end;

destructor TMessageBus.Destroy;
begin
  fContainer.Free;
  inherited;
end;

procedure TMessageBus.Send<T>(const aName: string; const aData: T);
begin
  TProc<T>(fContainer[aName])(aData);
end;

procedure TMessageBus.Subscribe<T>(const aName: string; const aProc: TProc<T>);
begin
  fContainer.AddOrSetValue(aName, IInterface(PPointer(@aProc)^));
end;

但是,除了省略任何验证代码之外,如果您发送的数据类型与订阅的数据类型不同,这很容易失败。因此,我将在这里使用TValue类型将传递的TProc<T>包装在TProc<TValue>中(来自System.Rtti)。但是请记住,TValue本身只允许编译器允许的类型转换,所以它不会将string转换为Integer或类似的类型-但如果需要,您可以自己添加以下内容:

代码语言:javascript
复制
type
  TMessageBus = class
  private
    fContainer: TDictionary<string, TProc<TValue>>;
  public
    constructor Create;
    destructor Destroy; override;
    procedure Send<T>(const aName: string; const aData: T);
    procedure Subscribe<T>(const aName: string; const aProc: TProc<T>);
  end;

constructor TMessageBus.Create;
begin
  fContainer := TDictionary<string, TProc<TValue>>.Create;
end;

destructor TMessageBus.Destroy;
begin
  fContainer.Free;
  inherited;
end;

procedure TMessageBus.Send<T>(const aName: string; const aData: T);
var
  proc: TProc<TValue>;
begin
  if fContainer.TryGetValue(aName, proc) then
    proc(TValue.From<T>(aData));
end;

procedure TMessageBus.Subscribe<T>(const aName: string; const aProc: TProc<T>);
begin
  fContainer.AddOrSetValue(aName,
    procedure(aValue: TValue)
    begin
      aProc(aValue.AsType<T>);
    end);
end;

例如,如果您现在调用mb.Send('somestring', 42);,它将在TValue.AsType中引发EInvalidCast异常,因为如前所述,它不能将传递的42转换为string,这是您在调用Subscribe时指定的。

票数 0
EN

Stack Overflow用户

发布于 2019-09-16 20:10:25

如果您有一个依赖于泛型类型T的字段,则必须使完整的类成为泛型,而不是方法:

代码语言:javascript
复制
type
  TMessageBus<T> = class
  private
    fContainer: TDictionary<String, TProc<T>>; // ERROR !!
  public
    procedure Send(aName: String; aData: T); // producer
    procedure Subscribe(aName: String; aProc: TProc<T>); // consumer
  end;
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57955941

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档