【问题标题】:How do I handle Delphi Simple types when using generics?使用泛型时如何处理 Delphi 简单类型?
【发布时间】:2023-03-07 06:28:01
【问题描述】:

一个小例子

TTest<T> = class
private
  f : T;
public
  function ToString : string;
end;

如果是一个对象,那么这应该可以工作

TTest<T>.ToString;
begin
  Result := f.ToString;
end;

但是当是一个整数时会发生什么?这在.net中没问题。当然。

我知道这行不通,但我如何编写代码以处理对象和简单类型?

【问题讨论】:

  • T 是一个类型,而不是一个值。您的代码应该看起来更像这样: var x: T;开始结果 := x.ToString;结束;

标签: delphi generics


【解决方案1】:

Delphi 不允许您执行您在第二个示例中尝试执行的操作的三个原因 - 对不受约束的类型参数类型的值调用 ToString 方法(或者至少我认为您正在尝试这样做显示,因为 TObject.ToString 是实例方法,而不是类方法,所以 T.ToString 即使对 TObject 也不起作用。

  1. Delphi 没有根类型系统,很少有所有类型通用的操作。这些操作——复制、赋值、创建位置(字段、局部变量、参数、数组)——是唯一保证对类型参数的所有可能值可用的操作。

  2. 从 1 开始,为什么操作仅限于这些?为什么不允许泛型类中的操作,而只在实例化时给出错误?嗯,第一部分原因是该设计最初旨在最大限度地与 .NET 和 dccil 兼容,因此 .NET 泛型不允许的东西在 Win32 泛型设计中没有显着的可供性。

    李>
  3. 设计的第二个理由是仅在实例化时检查是有问题的。使用这种方法的最著名的参数多态性实现是 C++ 模板,它还以其神秘的错误消息而闻名,例如尝试将错误类型的迭代器传递给算法,并收到关于未找到重载运算符的奇怪抱怨。多态性越深,问题越严重。事实上,很糟糕的是,C++ 本身正在以 C++ 0x Concepts 的形式来纠正这个错误。

希望您现在明白为什么不能使用通过约束不能保证可用的操作。不过,您可以相对轻松地摆脱这种限制,就像 Gamecat 建议的那样,通过以方法引用或接口实现的形式提供操作。

将来,Delphi for Win32 中的泛型可能会沿着类似的路线扩展到 C++ 0x 概念或 Haskell 类型类,这样类型参数可能会被限制为具有某些可用的方法、函数和运算符。如果它遵循类型类路线,那么类型推断也可能以这种方式进行。

【讨论】:

    【解决方案2】:

    最后一个例子不起作用。您需要添加约束才能使用方法。在这种情况下,TObject 就足够了:

    TTest<T: TObject>.ToString;
    begin
      Result := T.ToString;
    end;
    

    你可以使用简单的类型和不受限制的泛型,但是你的使用非常有限。因为唯一有效的操作是赋值和比较(相等和不相等)。

    在 Delphi 中,简单类型没有类,因此它们没有方法。 但您可以执行以下操作:

    type
      TToString<T> = reference to function(const AValue: T): string;
      TGenContainer<T> = class
      private
        FValue: T;
        FToString : TToString<T>;
      public
        constructor Create(const AToString: TToString<T>);
    
        function ToString: string;
    
        property Value: T read FValue write FValue;
      end;
    
    constructor TGenContainer<T>.Create(const AToString: TToString<T>);
    begin
      FToString := AToString;
    end;
    
    function TGenContainer<T>.ToString: string;
    begin
      Result := FToString(FValue);
    end;
    
    
    
    procedure TForm2.Button1Click(Sender: TObject);
    var
      gen : TGenContainer<Integer>;
    begin
      gen := TGenContainer<Integer>.Create(
        function(const AValue: Integer): string
        begin
          Result := IntToStr(AValue);
        end);
      try
        gen.Value := 17;
        Memo1.Lines.Add(gen.ToString);
      finally
        gen.Free;
      end;
    end;
    

    这很好用。

    【讨论】:

    • 是的,我知道,但我如何让它工作。它在 .net 中完美运行,因为一切都是对象。
    【解决方案3】:

    我想我可以将我的简单类型包装在对象中,并覆盖 ToString 函数,但这确实违背了泛型的目的。

    【讨论】:

    • 是的,简单类型没有方法。
    猜你喜欢
    • 1970-01-01
    • 2023-03-15
    • 1970-01-01
    • 1970-01-01
    • 2018-09-29
    • 2019-08-25
    • 1970-01-01
    • 2017-09-25
    • 1970-01-01
    相关资源
    最近更新 更多