繁体   English   中英

如何将通用T转换为TObject?

[英]How to cast generic T to a TObject?

我有一个方法需要返回一个对象。 当然,只有T 对象才有意义:

function TGrobber<T>.Swipe: TObject;
var
   current: T;
begin
    {
       If generic T is not an object, then there's nothing we can return
       But we'll do the caller a favor and not crash horribly.
    }
    if PTypeInfo(TypeInfo(T))^.Kind <> tkClass then
    begin
       Result := nil;
       Exit;
    end;

    //We *are* an object, return the object that we are.
    current := Self.SwipeT;

    Result := TObject(current); <--E2089 invalid class typecast
end;

如果T不是对象(例如IntegerStringOleVariant ),则它将返回nil ,并且不会严重崩溃。

如果我们是一个对象(例如TCustomerTPatronTSalesOrderTShape ),那么我们可以很好地返回该对象。

我不想混淆这个问题。 但是,如果您查看IEnumerable ,则会看到实际情况。

奖励阅读

回答

我将让TLama复制/粘贴答案以得到他的荣誉:

function TGrobber<T>.Swipe: TObject;
var
   current: T;
   v: TValue;
begin
    current := Self.SwipeT;
    v := TValue.From<T>(current);
    {
       If generic T is not an object, then there's nothing we can return
       But we'll do the caller a favor and not crash horribly.
    }
    if not v.IsObject then
    begin
       Result := nil;
       Exit;
    end;

    Result := v.AsObject;
end;

我看到两个主要选项。 如果泛型类型必须是类类型,并且在编译时就知道了,则应将约束应用于该类型:

type
  TGrobber<T: class> = class
    ....
  end;

或者,如果类型必须从特定的类派生,则可以这样指定约束:

type
  TGrobber<T: TMyObject> = class
    ....
  end;

一旦应用了约束,那么您就需要直接分配。

Result := current;

这是可能的,因为编译器会对您的泛型类型施加约束。 因此知道该分配对所有可能的实例均有效。

我要评论的是,泛型类具有返回TObject的函数似乎很奇怪。 您的函数为什么不返回T

如果您不能约束,那么简单的指针类型转换是最干净的方法:

Result := PObject(@current)^;

显然,您需要检查T是一个类类型,您已经证明了它是熟练的代码。

值得一提的是,由于使用Delphi XE7,使用System.GetTypeKind检查类型的类型更加简单:

if GetTypeKind(T) = tkClass then
  Result := PObject(@current)^
else
  Result := nil;

是的,可以通过TValue完成,但这不是正确的方法。 我相信让编译器验证它是TObject(或后代)要好得多。

unit GrobberU;

interface

type
  TGrobber<T : Class> = class
  public
    function Swipe: TObject;
  end;

implementation

{ TGrobber<T> }

function TGrobber<T>.Swipe: TObject;
begin
  Result := T;
end;

end.

然后您可以测试它:

procedure TForm37.FormCreate(Sender: TObject);
var
  Grobber1 : TGrobber<TEdit>;
  Grobber2 : TGrobber<Integer>; <-- Does not compile    
begin
end;

在此处输入图片说明

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM