Delphi and generics: some examples of “E2015: Operator not applicable to this operand type”
Posted by jpluimers on 2019/12/24
I don’t have enough time right now to elaborate on the code, so below is a an example of where I bumped into the very non-descriptive [WayBack/Archive.is] E2015: Operator not applicable to this operand type when using generics in Delphi.
Most have to do with comparing types (one of which is similar to comparing interfaces where you need to have a GUID in order to get an as
comparison working, see Source: Delphi – Using FastMM4 part 2: TDataModule descendants exposing interfaces, or the introduction of a TInterfacedDataModule).
Like most post-Delphi 2007 language features in Delphi, generics still have rough edges. I doubt this will change anytime soon and I am not alone in this.
The documentation never got update to cover situations involving generics ([Archive.is] E2015 Operator not applicable to this operand type (Delphi) – RAD Studio), so basically this to show some examples you might bump into as well.
Note the code below usually is an indication of code-smell, as was the more elaborate situation I had to use it in. A long term solution for that code was to introduce more polymorphism.
A shorter term solution involves either the use of local variables or type-casting (for the latter, see [WayBack] delphi – Cannot compile constrained generic method – Stack Overflow)
–jeroen
program E2015WithGenerics; | |
uses | |
System.SysUtils; | |
{$APPTYPE CONSOLE} | |
{$R *.res} | |
type | |
TMyAncestor = class | |
end; | |
TMyClass = class(TMyAncestor) | |
strict protected | |
function GetClassInstance<T: class>: T; | |
function GetTMyAncestorInstance<T: TMyAncestor>: T; | |
// function GetTMyClassInstance<T: TMyClass>: T; // [dcc32 Error] E2086 Type 'TMyClass' is not yet completely defined | |
end; | |
function TMyClass.GetClassInstance<T>: T; | |
var | |
lClassType: TClass; | |
begin | |
lClassType := T; | |
if lClassType = TMyClass then | |
begin | |
Result := T(Self) | |
end | |
else if T = TMyClass then | |
begin | |
Result := T(Self) | |
end | |
// else if lClassType is TMyClass then // [dcc32 Error] E2015 Operator not applicable to this operand type | |
// begin | |
// Result := T(Self) | |
// end | |
// else if T is TMyClass then // [dcc32 Error] E2015 Operator not applicable to this operand type | |
// begin | |
// Result := T(Self) | |
// end | |
else if lClassType.InheritsFrom(TMyClass) then | |
begin | |
Result := T(Self) | |
end | |
else if T.InheritsFrom(TMyClass) then | |
begin | |
Result := T(Self) | |
end | |
else | |
begin | |
raise ENotSupportedException.CreateFmt('GetClassInstance fails for class %s', [lClassType.ClassName]); | |
end; | |
end; | |
function TMyClass.GetTMyAncestorInstance<T>: T; | |
var | |
lClassType: TClass; | |
begin | |
lClassType := T; | |
if lClassType = TMyClass then | |
begin | |
Result := T(Self) | |
end | |
// else if T = TMyClass then // [dcc32 Error] E2015 Operator not applicable to this operand type | |
// begin | |
// Result := T(Self) | |
// end | |
// else if lClassType is TMyClass then // [dcc32 Error] E2015 Operator not applicable to this operand type | |
// begin | |
// Result := T(Self) | |
// end | |
// else if T is TMyClass then // [dcc32 Error] E2015 Operator not applicable to this operand type | |
// begin | |
// Result := T(Self) | |
// end | |
else if lClassType.InheritsFrom(TMyClass) then | |
begin | |
Result := T(Self) | |
end | |
else if T.InheritsFrom(TMyClass) then | |
begin | |
Result := T(Self) | |
end | |
else | |
begin | |
raise ENotSupportedException.CreateFmt('GetTMyAncestorInstance fails for class %s', [lClassType.ClassName]); | |
end; | |
end; | |
//function TMyClass.GetTMyClassInstance<T>: T; | |
//begin | |
////… | |
//end; | |
begin | |
end. |
Leave a Reply