How can I cast an object to a generic?

后端 未结 2 1896
余生分开走
余生分开走 2021-02-04 17:39

I\'m trying to cast a returned base object to it\'s specific generic type. The code below should work I think but generates an internal compiler error, is there another way to

2条回答
  •  独厮守ぢ
    2021-02-04 18:23

    The answer above from Andreas is brilliant. It's really helped my use of generics in Delphi. Please then forgive me Andreas as I wonder if DynamicCast is a little complicated. Please correct me if I'm wrong but the following should be a little more concise, safe, fast (no string comparisons) and still as functional.

    Really all I've done is use the class constraint on the DynamicCast type params to allow the compiler to do a bit of work (as the original will always except with non-class parameters) and then use the TObject.InheritsFrom function to check for type compatibility.

    I've also found the idea of a TryCast function quite useful (it's a common task for me anyway!)

    This is of course unless I've missed the point somewhere in trawling the class parents for matching names... which IMHO is a little dangerous given that type names may match for non compatible classes in different scopes.

    Anyway, here's my code (works for Delphi XE3... D2009 compatible version of TryCast follows after).

    type
      TTypeCast = class
      public
        // ReinterpretCast does a hard type cast
        class function ReinterpretCast(const Value): ReturnT;
        // StaticCast does a hard type cast but requires an input type
        class function StaticCast(const Value: T): ReturnT;
        // Attempt a dynamic cast, returning True if successful
        class function TryCast(const Value: T; out Return: ReturnT): Boolean;
        // DynamicCast is like the as-operator. It checks if the object can be typecasted
        class function DynamicCast(const Value: T): ReturnT;
      end;
    
    implementation
    
    uses
      System.SysUtils;
    
    
    class function TTypeCast.ReinterpretCast(const Value): ReturnT;
    begin
      Result := ReturnT(Value);
    end;
    
    class function TTypeCast.StaticCast(const Value: T): ReturnT;
    begin
      Result := ReinterpretCast(Value);
    end;
    
    class function TTypeCast.TryCast(const Value: T; out Return: ReturnT): Boolean;
    begin
      Result := (not Assigned(Value)) or Value.InheritsFrom(ReturnT);
      if Result then
        Return := ReinterpretCast(Value);
    end;
    
    class function TTypeCast.DynamicCast(const Value: T): ReturnT;
    begin
      if not TryCast(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;
    

    As promised the D2009 version (needs some small effort to get to the class of ReturnT).

    class function TTypeCast.TryCast(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(Value)
        else
          Result := False;
      end;
    end;
    

提交回复
热议问题