Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi 如何将对象强制转换为泛型?_Delphi_Generics_Delphi 2009 - Fatal编程技术网

Delphi 如何将对象强制转换为泛型?

Delphi 如何将对象强制转换为泛型?,delphi,generics,delphi-2009,Delphi,Generics,Delphi 2009,我试图将返回的基对象强制转换为它的特定泛型类型。我认为下面的代码应该可以工作,但会生成一个内部编译器错误,是否有其他方法可以做到这一点 type TPersistGeneric<T> = class private type TPointer = ^T; public class function Init : T; end; class function TPersistGeneric<T>.Init : T; var o

我试图将返回的基对象强制转换为它的特定泛型类型。我认为下面的代码应该可以工作,但会生成一个内部编译器错误,是否有其他方法可以做到这一点

type
  TPersistGeneric<T> = class
  private
  type
    TPointer = ^T;
  public
    class function  Init : T;
  end;

class function  TPersistGeneric<T>.Init : T;
var
  o : TXPersistent; // root class
begin
  case PTypeInfo(TypeInfo(T))^.Kind of
    tkClass : begin
                // xpcreate returns txpersistent, a root class of T
                o := XPCreate(GetTypeName(TypeInfo(T))); // has a listed of registered classes
                result := TPointer(pointer(@o))^;
              end;
    else
      result := Default(T);
  end;
end;
类型
TPersistGeneric=class
私有的
类型
T指针=^T;
公众的
类函数Init:T;
结束;
类函数TPersistGeneric.Init:T;
变量
o:txpersist;//根类
开始
案例PTypeInfo(TypeInfo(T))^。类型
tkClass:开始
//xpcreate返回txpersistent,一个T的根类
o:=XPCreate(GetTypeName(TypeInfo(T));//有一个注册类的列表
结果:=TPointer(指针(@o))^;
结束;
其他的
结果:=默认值(T);
结束;
结束;

我正在使用一个typecast助手类来执行类型转换,并检查这两个类是否兼容

class function TPersistGeneric<T>.Init: T;
var
  o : TXPersistent; // root class
begin
  case PTypeInfo(TypeInfo(T))^.Kind of
    tkClass : begin
                // xpcreate returns txpersistent, a root class of T
                o := XPCreate(GetTypeName(TypeInfo(T))); // has a listed of registered classes
                Result := TTypeCast.DynamicCast<TXPersistent, T>(o);
              end;
    else
      result := Default(T);
  end;
类函数TPersistGeneric.Init:T;
变量
o:txpersist;//根类
开始
案例PTypeInfo(TypeInfo(T))^。类型
tkClass:开始
//xpcreate返回txpersistent,一个T的根类
o:=XPCreate(GetTypeName(TypeInfo(T));//有一个注册类的列表
结果:=TTypeCast.DynamicCast(o);
结束;
其他的
结果:=默认值(T);
结束;
下面是课堂:

type
  TTypeCast = class
  public
    // ReinterpretCast does a hard type cast
    class function ReinterpretCast<ReturnT>(const Value): ReturnT;
    // StaticCast does a hard type cast but requires an input type
    class function StaticCast<T, ReturnT>(const Value: T): ReturnT;
    // DynamicCast is like the as-operator. It checks if the object can be typecasted
    class function DynamicCast<T, ReturnT>(const Value: T): ReturnT;
  end;

class function TTypeCast.ReinterpretCast<ReturnT>(const Value): ReturnT;
begin
  Result := ReturnT(Value);
end;

class function TTypeCast.StaticCast<T, ReturnT>(const Value: T): ReturnT;
begin
  Result := ReinterpretCast<ReturnT>(Value);
end;

class function TTypeCast.DynamicCast<T, ReturnT>(const Value: T): ReturnT;
var
  TypeT, TypeReturnT: PTypeInfo;
  Obj: TObject;
  LClass: TClass;
  ClassNameReturnT, ClassNameT: string;
  FoundReturnT, FoundT: Boolean;
begin
  TypeT := TypeInfo(T);
  TypeReturnT := TypeInfo(ReturnT);
  if (TypeT = nil) or (TypeReturnT = nil) then
    raise Exception.Create('Missing Typeinformation');
  if TypeT.Kind <> tkClass then
    raise Exception.Create('Source type is not a class');
  if TypeReturnT.Kind <> tkClass then
    raise Exception.Create('Destination type is not a class');

  Obj := TObject(Pointer(@Value)^);
  if Obj = nil then
    Result := Default(ReturnT)
  else
  begin
    ClassNameReturnT := UTF8ToString(TypeReturnT.Name);
    ClassNameT := UTF8ToString(TypeT.Name);
    LClass := Obj.ClassType;
    FoundReturnT := False;
    FoundT := False;
    while (LClass <> nil) and not (FoundT and FoundReturnT) do
    begin
      if not FoundReturnT and (LClass.ClassName = ClassNameReturnT) then
        FoundReturnT := True;
      if not FoundT and (LClass.ClassName = ClassNameT) then
        FoundT := True;
      LClass := LClass.ClassParent;
    end;
    //if LClass <> nil then << TObject doesn't work with this line
    if FoundT and FoundReturnT then
      Result := ReinterpretCast<ReturnT>(Obj)
    else
    if not FoundReturnT then
      raise Exception.CreateFmt('Cannot cast class %s to %s',
                                [Obj.ClassName, ClassNameReturnT])
    else
      raise Exception.CreateFmt('Object (%s) is not of class %s',
                                [Obj.ClassName, ClassNameT]);
  end;
end;
类型
TTypeCast=class
公众的
//ReinterpretCast执行硬类型转换
类函数ReinterpretCast(const值):ReturnT;
//StaticCast执行硬类型转换,但需要输入类型
类函数StaticCast(const值:T):ReturnT;
//DynamicCast类似于as操作符。它检查对象是否可以进行类型转换
类函数DynamicCast(const值:T):ReturnT;
结束;
类函数TTypeCast.ReinterpretCast(常量值):ReturnT;
开始
结果:=返回t(值);
结束;
类函数TTypeCast.StaticCast(常量值:T):ReturnT;
开始
结果:=重新解释投射(值);
结束;
类函数TTypeCast.DynamicCast(常量值:T):ReturnT;
变量
TypeT,TypeReturnT:PTypeInfo;
对象:对象;
l类:TClass;
ClassNameReturnT,ClassNameT:字符串;
FoundReturnT,FoundT:布尔值;
开始
类型T:=类型信息(T);
TypeReturnT:=TypeInfo(ReturnT);
如果(TypeT=nil)或(TypeReturnT=nil),则
引发异常。创建('缺少类型信息');
如果类型为TK类,则
引发异常。Create('源类型不是类');
如果TypeReturnT.Kind tkClass那么
引发异常。创建('目标类型不是类');
Obj:=TObject(指针(@Value)^);
如果Obj=nil,则
结果:=默认值(ReturnT)
其他的
开始
ClassNameReturnT:=UTF8ToString(TypeReturnT.Name);
ClassNameT:=UTF8ToString(TypeT.Name);
LClass:=Obj.ClassType;
FoundReturnT:=假;
found:=假;
而(LClass nil)和非(FoundT和FoundReturnT)则
开始
如果未找到Returnt和(LClass.ClassName=ClassNameReturnT),则
FoundReturnT:=真;
如果未找到和(LClass.ClassName=ClassNameT),则
FoundT:=正确;
LClass:=LClass.ClassParent;
结束;

//如果L等级为零,那么上面安德烈亚斯的回答是精彩的。它确实帮助了我在Delphi中使用泛型。请原谅我,安德烈亚斯,我想知道DynamicCast是否有点复杂。如果我错了,请纠正我,但以下内容应该更简洁、安全、快速(无字符串比较),并且仍然具有功能性

实际上,我所做的只是在DynamicCast类型参数上使用类约束,以允许编译器做一些工作(原始编译器总是会做一些工作,非类参数除外),然后使用TObject.InheritsFrom函数检查类型兼容性

我还发现TryCast函数的想法非常有用(不管怎样,这对我来说是一项常见的任务!)

这当然是,除非我在搜寻班级家长的名字时忽略了重点。。。考虑到类型名可能与不同作用域中的不兼容类相匹配,这有点危险

无论如何,下面是我的代码(适用于Delphi XE3…之后是TryCast的D2009兼容版本)

类型
TTypeCast=class
公众的
//ReinterpretCast执行硬类型转换
类函数ReinterpretCast(const值):ReturnT;
//StaticCast执行硬类型转换,但需要输入类型
类函数StaticCast(const值:T):ReturnT;
//尝试动态强制转换,如果成功,则返回True
类函数TryCast(常量值:T;输出返回:ReturnT):布尔;
//DynamicCast类似于as操作符。它检查对象是否可以进行类型转换
类函数DynamicCast(const值:T):ReturnT;
结束;
实施
使用
System.SysUtils;
类函数TTypeCast.ReinterpretCast(常量值):ReturnT;
开始
结果:=返回t(值);
结束;
类函数TTypeCast.StaticCast(常量值:T):ReturnT;
开始
结果:=重新解释投射(值);
结束;
类函数TTypeCast.TryCast(常量值:T;输出返回:ReturnT):布尔;
开始
结果:=(未赋值(Value))或Value.InheritsFrom(ReturnT);
如果结果是这样的话
返回:=重新解释广播(值);
结束;
类函数TTypeCast.DynamicCast(常量值:T):ReturnT;
开始
如果不是TryCast(值、结果),则
//如果TryCast返回false,则将明确指定值
提升EInvalidCast.CreateFmt('从%s(%s)到%s的类类型转换无效,',
[T.ClassName,Value.ClassName,ReturnT.ClassName]);
结束;
正如D2009版本所承诺的那样(需要一些小的努力才能进入ReturnT类)

类函数TTypeCast.TryCast(常量值:T;输出返回:ReturnT):布尔;
变量
LReturnTypeInfo:PTypeInfo;
LReturnClass:TClass;
开始
结果:=真;
如果未分配(值),则
Return:=默认值(ReturnT)
其他的
开始
LReturnTypeInfo:=类型信息(ReturnT);
LReturnClass:=GetTypeData(LReturnTypeInfo).ClassType;
如果值。从(LRetu)继承
type
  TTypeCast = class
  public
    // ReinterpretCast does a hard type cast
    class function ReinterpretCast<ReturnT>(const Value): ReturnT;
    // StaticCast does a hard type cast but requires an input type
    class function StaticCast<T, ReturnT>(const Value: T): ReturnT;
    // Attempt a dynamic cast, returning True if successful
    class function TryCast<T, ReturnT: class>(const Value: T; out Return: ReturnT): Boolean;
    // DynamicCast is like the as-operator. It checks if the object can be typecasted
    class function DynamicCast<T, ReturnT: class>(const Value: T): ReturnT;
  end;

implementation

uses
  System.SysUtils;


class function TTypeCast.ReinterpretCast<ReturnT>(const Value): ReturnT;
begin
  Result := ReturnT(Value);
end;

class function TTypeCast.StaticCast<T, ReturnT>(const Value: T): ReturnT;
begin
  Result := ReinterpretCast<ReturnT>(Value);
end;

class function TTypeCast.TryCast<T, ReturnT>(const Value: T; out Return: ReturnT): Boolean;
begin
  Result := (not Assigned(Value)) or Value.InheritsFrom(ReturnT);
  if Result then
    Return := ReinterpretCast<ReturnT>(Value);
end;

class function TTypeCast.DynamicCast<T, ReturnT>(const Value: T): ReturnT;
begin
  if not TryCast<T, ReturnT>(Value, Result) then
    //Value will definately be assigned is TryCast returns false
    raise EInvalidCast.CreateFmt('Invalid class typecast from %s(%s) to %s',
      [T.ClassName, Value.ClassName, ReturnT.ClassName]);
end;
class function TTypeCast.TryCast<T, ReturnT>(const Value: T; out Return: ReturnT): Boolean;
var
  LReturnTypeInfo: PTypeInfo;
  LReturnClass: TClass;
begin
  Result := True;
  if not Assigned(Value) then
    Return := Default(ReturnT)
  else
  begin
    LReturnTypeInfo := TypeInfo(ReturnT);
    LReturnClass := GetTypeData(LReturnTypeInfo).ClassType;
    if Value.InheritsFrom(LReturnClass) then
      Return := ReinterpretCast<ReturnT>(Value)
    else
      Result := False;
  end;
end;