Watch, Follow, &
Connect with Us
Public Report
Report From: Delphi-BCB/RTL/Delphi/Other RTL    [ Add a report in this area ]  
Report #:  123729   Status: Open
TValue.AsType<T> does not work properly for interfaces
Project:  Delphi Build #:  XE, ... XE5
Version:    19.2 Submitted By:   Stefan Glienke
Report Type:  Basic functionality failure Date Reported:  4/1/2014 4:26:35 AM
Severity:    Serious / Highly visible problem Last Updated: 4/7/2014 1:29:19 AM
Platform:    All platforms Internal Tracking #:   49465
Resolution: None (Resolution Comments) Resolved in Build: : None
Duplicate of:  None
Voting and Rating
Overall Rating: No Ratings Yet
0.00 out of 5
Total Votes: 10
Description
When using AsType<T> it only works when T is either IInterface or the exact same type as the TValue instance holds.

But actually it should also work for any T that is a parent type of the type that the TValue is holding.

The cause is the ConvIntf2Intf routine. I added a suggestion on how to fix it to the testcase.
Steps to Reproduce:
compile and run attachment

expected: PASS PASS
actual: FAIL PASS

--------
program QC123729;

{$APPTYPE CONSOLE}

uses
  Rtti,
  SysUtils,
  TypInfo;

type
  IFoo = interface
  end;

  IBar = interface(IFoo)
  end;

  TBar = class(TInterfacedObject, IBar)
  end;

  IBaz = interface
  end;

function ConvIntf2Intf(const ASource: TValue; ATarget: PTypeInfo; out AResult: TValue): Boolean;
var
  src: Pointer;
  typeData: PTypeData;
begin
  Result := (ATarget = TypeInfo(IInterface)) or (ATarget = ASource.TypeInfo);
  if not Result then
  begin
    typeData := GetTypeData(ASource.TypeInfo);
    while (typeData <> nil) and (typeData.IntfParent <> nil) do
    begin
      if typeData.IntfParent^ = ATarget then
      begin
        Result := True;
        Break;
      end;
      typeData := GetTypeData(typeData.IntfParent^);
    end;
  end;

  if Result then
  begin
    ASource.ExtractRawDataNoCopy(@src);
    TValue.Make(@src, ATarget, AResult);
  end;
end;

procedure Test;
var
  foo: IFoo;
  bar: IBar;
  v, v2: TValue;
begin
  bar := TBar.Create;
  foo := bar; // <- assignment compatible
  try
    v := TValue.From<IBar>(bar);
    foo := v.AsType<IFoo>;   // <<--------- EInvalidCast exception occurs
    Writeln('PASS');
  except
    on E: Exception do
      Writeln('FAIL');
  end;

  if ConvIntf2Intf(v, TypeInfo(IFoo), v2) then
    Writeln('PASS')
  else
    Writeln('FAIL');
end;

begin
  Test;
end.
--------
Workarounds
None
Attachment
QC123729.zip
Comments

None

Server Response from: ETNACODE01