1

Why is it that this code can not cast to IDeletableNode from a generics list that requires that specific interface.

This code sample can not execute the IDeletableNode.Delete procedure no matter how I cast it.

    unit DeletableGenericsTest;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, xmldom, XMLDoc, XMLIntf, Generics.Collections;

type

  IDeletableNode = interface(IXMLNode)
    ['{04D7A0C0-8E87-412B-BC55-230C7080D410}']
    procedure Delete;
  end;

  INodeOfData = interface(IDeletableNode)
     ['{368917D8-402F-4BA2-8BC5-B0DB51B1BAE9}']
     function Get_MyKey : string;
     property MyKey : string read Get_MyKey;
  end;

  TDeletableList<T: IDeletableNode> = class(TList<T>)
     procedure DeleteAll;
  end;

  TNodeOfData = class(TXMLNode, INodeOfData)
  protected
     function Get_MyKey: string;
  public
     procedure Delete;
  end;

  TForm1 = class(TForm)
  private
    fListOfNodes : TDeletableList<TNodeOfData>;
  public
    { Public declarations }
  end;


var
  Form1: TForm1;

implementation

{$R *.dfm}

{ TDeletableList<T> }

procedure TDeletableList<T>.DeleteAll;
var
index : Integer;
begin
   for index := Self.Count - 1 downto 0 do
       Self[index].Delete;
end;

{ TNodeOfData }

procedure TNodeOfData.Delete;
begin
   // delete some stuff;
end;

function TNodeOfData.Get_MyKey: string;
begin
   result := '123ABC';
end;

end.

Is there something that I am missing here or is this correct?

morrisseyd
  • 176
  • 1
  • 2
  • 9
  • Where is the code that fails? Where are the type-casts you say don't work? – Remy Lebeau Oct 02 '15 at 00:00
  • Sorry, the line "Self[index].Delete;" says that Delete not declared and casting it to IDeletableNode is an invalid operation. – morrisseyd Oct 02 '15 at 02:28
  • 1
    Using the code you have shown, `Self[index].Delete` works fine for me when I try it in XE2 (I did define my own `IXMLNode` and `TXMLNode` types. Are you using the ones in the `Xml.XmlIntf` and `Xml.XmlDoc` units instead?). `TNodeOfData.Delete` is called, as expected. Error Insight says `Delete` is undeclared, but the code compiles and runs. If you are having an actual compiler error, please provide a complete [MCVE](http://stackoverflow.com/help/mcve) to reproduce the error. – Remy Lebeau Oct 02 '15 at 03:37
  • I have updated the example code above to reflect the actual failing example. I am using XE7 and this is a single form demo project with this one form unit. – morrisseyd Oct 02 '15 at 05:11
  • Sorry the previous edit did not have the erroneous interface hierarchy. – morrisseyd Oct 02 '15 at 05:27
  • posible dublicate of http://stackoverflow.com/questions/19682057/delphi-interface-inheritance-with-generics – Jens Borrisholt Oct 02 '15 at 05:37
  • Sorry another apology, the tag should have been xe7 and not xe2. – morrisseyd Oct 02 '15 at 05:48
  • 1
    Thanks for the reference Jens however this issue appears to be about code that was using a comma in place of a semi-colon when declaring more than one generic type. – morrisseyd Oct 02 '15 at 05:51
  • 1
    `TNodeOfData` does not implement `IDeletableNode`. Try declaring it as `TNodeOfData = class(TXMLNode, INodeOfData, IDeletableNode)`. – David Heffernan Oct 02 '15 at 06:02
  • For the history of it (why you have to list all interfaces in the class declaration as David suggest above) see http://stackoverflow.com/q/8467945/723693 – ain Oct 02 '15 at 06:29
  • Thanks David. The issue here is that INodeOfData the interface inherits from IDeletableNode. I tried your solution and it worked in the test example however in the real application there are dozens of interfaces that need to inherit IDeletableNode and pushing it directly to declaration in the objects is causing circular reference issues. – morrisseyd Oct 02 '15 at 06:30
  • 1
    That's easy to fix by pushing the interface definitions into separate unit(s) that can be used by all the units that implement and use them. – David Heffernan Oct 02 '15 at 07:18
  • Next time, please post code that is compilable (console app preferably) and state the error message and the line that fails. Makes it easier for everyone to help. – LU RD Oct 02 '15 at 07:55

1 Answers1

2

The code in your question fails with this error:

[dcc32 Error] E2514 Type parameter 'T' must support interface 'IDeletableNode'

at this line:

fListOfNodes : TDeletableList<TNodeOfData>;

The compiler has told you, quite clearly, that TNodeOfData must implement IDeletableNode, which it does not. This is so because of the constraint on the generic parameter:

TDeletableList<T: IDeletableNode> = class(TList<T>)

So change

TNodeOfData = class(TXMLNode, INodeOfData)

to

TNodeOfData = class(TXMLNode, IDeletableNode, INodeOfData)

and your code will compile.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490