【问题标题】:Typecast Generic type to other type将泛型类型转换为其他类型
【发布时间】:2014-10-30 10:29:23
【问题描述】:

我有一个基类

 TEventMulticaster = class(Tobject)
 public
   procedure Notify(aMap: WideString);
 end;

 procedure TEventMulticaster.Notify(aMap: WideString);
 begin
  // Do something 
 end;

还有一个派生的泛型类

  TEventMulticaster<T> = class(TEventMulticaster)
   public
     procedure Notify(aMap: T ); reintroduce;
   end;


  procedure TEventMulticaster<T>.Notify(aMap: T);
  begin
    inherited Notify(aMap)  // ERROR
  end;

当基类 Notify 被调用时,它会给我错误“不兼容的类型:'WideString' 和 'T'” 当我做**Notify(WideString(aMap))** 时,它说无效的类型转换

我的问题是如何将泛型类型转换为“WideString”,以便我可以调用基类notify

【问题讨论】:

  • 您不能将任意泛型参数类型转换为WideString。你为什么要这样做。如果aMapTMainForm,代表您的应用程序的主要形式的类,您会期望发生什么?在实现泛型方法时,您必须考虑到,泛型类型绝对可以是任何东西。现在,您可以应用约束,但它们有些受限。另外,你为什么使用WideString。除非您正在调用 COM 方法,否则您应该停止使用它。使用stringUnicodeString 的别名。
  • 这对我来说没有意义,但是,inherited Notify(WideString(TValue.From&lt;T&gt;(aMap).AsString));。或inherited Notify(TValue.From&lt;T&gt;(aMap).AsType&lt;WideString&gt;);.
  • 我这样做是因为超过 10 个类是从基类“TEventMulticaster”派生的,它们都在做同样的事情,但类型不同,所以我用泛型函数创建泛型类并执行我的操作.并且 aMap 不是类型类。
  • 你的问题的答案是你不能这样做。这对你不是很有帮助。除非您提出潜在问题,否则我们很难为您提供更一般的建议,我认为这是您所需要的。至于您所说的“aMap 不是类型类”,它对编译器并不真正持有任何货币。就它而言,T 可以是任何东西,因为你说过它可以是任何东西。这几乎就是泛型存在的理由。

标签: delphi generics delphi-xe2 delphi-xe5 delphi-xe4


【解决方案1】:
procedure TEventMulticaster<T>.Notify(aMap: T);
begin
  inherited Notify(aMap);
end;

这里有aMap,它是一个泛型参数,类型为TT 类型对此没有任何限制。它可以是任何类型。您正在寻求将aMap 转换为WideString。编译器根本无法做到这一点。没有可以接受任意类型的参数并将其转换为WideString 的总体转换。

您可以将aMap 推入TValue,然后调用TValueToString 方法。编译器至少会对此感到满意:

inherited Notify(TValue.From<T>(aMap).ToString);

这可能会如您所愿。或者也许不是。这完全取决于T 碰巧是什么。如果TIntegerstring 之类的基本类型,那么TValue.ToString 几乎肯定会达到您的预期。如果T 更深奥,那么谁知道这段代码是否会按照您的预期运行。您当然没有向我们说明如何将任意类型转换为文本。


我怀疑你没有掌握泛型的一点是编译器必须知道如何编译方法而不知道泛型类型是什么。在 cmets 中,您声明:

aMap 不是类型类

虽然您可能知道,但编译器不知道。从编译器的角度来看,T 可以是任何东西。泛型与在实例化后进行编译的 Smalltalk/C++ 模板非常不同。

泛型功能确实允许您对泛型类型应用约束。然而,这些都是相当有限的。您不能应用这样的约束:type T 将有一个明确定义的隐式转换为WideString

正如我之前对您说过的,我感觉到您正在为对泛型的理解而苦苦挣扎。我觉得你提出潜在的问题比你提出解决方案更有效率。


最后一点。 WideString 类型是 COM BSTR 字符串类型的包装器。在现代 Unicode 感知 Delphi 中,您仅在使用 COM 编写互操作代码时使用WideString。您应该使用string 而不是WideStringstring 类型是本机 Delphi Unicode 字符串类型 UnicodeString 的别名。

【讨论】:

  • 推送到 tvalue 然后调用基本函数就可以了,非常感谢......
  • 如果 T 是记录数组类型,那么我该如何提取它
  • 嗯,这就是我的意思。你不能指望 TValue 能够处理所有事情。我想你可能需要问一个新问题。我敦促您提出您面临的问题,而不是询问您的解决方案。
  • 本质上,泛型迎合了编译时间的差异。您正在寻找运行时差异。这可能意味着您需要 RTTI。
【解决方案2】:

您正在寻找这样的东西吗?

TEventMulticaster = class
end;

TEventMulticaster<T> = class( TEventMulticaster )
public
  procedure Notify( AMsg : T );
end;

TEventMaster = class
private
  FEvents : TList<TEventMulticaster>;
public
  procedure Notify<T>( AMsg : T );
end;

procedure TEventMaster.Notify<T>( AMsg : T );
var
  LEvent : TEventMulticaster;
begin
  for LEvent in FEvents do
    if LEvent is TEventMulticaster<T> then
      ( LEvent as TEventMulticaster<T> ).Notify( AMsg );
end;

【讨论】:

  • 不完全是我所期望的,因为在我的问题中我正在调用我的基类的非泛型函数。
猜你喜欢
  • 2019-09-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-10-14
相关资源
最近更新 更多