How do I implement two methods from two interfaces with the same name?

Viewed 68

I'm having some trouble using method resolution clause in Delphi 10.4.

Say I want to create a cat and a dog repository. In this case the TAnimalRepository has both cats and dogs, so I would like to implement both the cat and dog interfaces in that class.

Example:

IRepositoryBase<T> = Interface
    ['{776B3383-AF6E-44F7-BF32-1ACCF9A6C964}']
    function GetAll(items: TList<T>; out errMsg: String): Boolean;
End;

TCat = class
end;

ICatRepository = Interface(IRepositoryBase<TCat>)
    ['{C37CF989-E069-450B-8937-E46F6BFA66E9}']
    function GetAll(items: TList<TCat>; out errMsg: String): Boolean;
End;

TDog = class
end;

IDogRepository = Interface(IRepositoryBase<TDog>)
    ['{56B28463-0007-497E-8015-D794873328FF}']
    function GetAll(items: TList<TDog>; out errMsg: String): Boolean;
End;

TAnimalRepository = class(TInterfacedObject, ICatRepository, IDogRepository)
    function ICatRepository.GetAll = GetAllCats;
    function IDogRepository.GetAll = GetAllDogs;
public
    function GetAllCats(items: TList<TCat>; out errMsg: String): Boolean;
    function GetAllDogs(items: TList<TDog>; out errMsg: String): Boolean;
end;

Since we have two different methods with the same name, I have tried to use method resolution clause as described here: https://docwiki.embarcadero.com/RADStudio/Sydney/en/Implementing_Interfaces

function ICatRepository.GetAll = GetAllCats;
function IDogRepository.GetAll = GetAllDogs;

But when I try to compile the above code, it fails with:

[dcc32 Error] MethodResolutionExample.dpr(33): E2291 Missing implementation of interface method MethodResolutionExample.IRepositoryBase<MethodResolutionExample.TDog>.GetAll

[dcc32 Error] MethodResolutionExample.dpr(33): E2291 Missing implementation of interface method MethodResolutionExample.IRepositoryBase<MethodResolutionExample.TCat>.GetAll

Then I thought, why not try to add a method resolution for their inherited interface IRepositoryBase as well, like this:

TAnimalRepository = class(TInterfacedObject, ICatRepository, IDogRepository)
    function ICatRepository.GetAll = GetAllCats;
    function IRepositoryBase<TCat>.GetAll = GetAllCats;  // <--- This
    function IDogRepository.GetAll = GetAllDogs;
    function IRepositoryBase<TDog>.GetAll = GetAllDogs;  // <--- This
public
    function GetAllCats(items: TList<TCat>; out errMsg: String): Boolean;
    function GetAllDogs(items: TList<TDog>; out errMsg: String): Boolean;
end;

But now it gets funky. It looks like the compiler can't handle generics in the method resolution clause, because I get a lot of parsing errors now, beginning with:

[dcc32 Error] MethodResolutionExample.dpr(35): E2023 Function needs result type

It complains about this line:

function IRepositoryBase<TCat>.GetAll = GetAllCats;

What am I doing wrong? Do I really have to split my TAnimalRepository up in two different classes?

Thanks in advance.

Oh, one important note. I can get it to work, if my ICatRepository and IDogRepository doesn't inherit from IRepositoryBase. But in my use case, I would like them to inherit from the base class.

1 Answers

You need to get rid of the additional declarations of GetAll in ICatRepository and IDogRepository. If you just leave the GUID in these interfaces all works as expected.

type
  IRepositoryBase<T> = interface
    ['{776B3383-AF6E-44F7-BF32-1ACCF9A6C964}']
    function GetAll(items: TList<T>; out errMsg: string): Boolean;
  end;

  TCat = class
  end;

  ICatRepository = interface(IRepositoryBase<TCat>)
    ['{C37CF989-E069-450B-8937-E46F6BFA66E9}']
  end;

  TDog = class
  end;

  IDogRepository = interface(IRepositoryBase<TDog>)
    ['{56B28463-0007-497E-8015-D794873328FF}']
  end;

  TAnimalRepository = class(TInterfacedObject, ICatRepository, IDogRepository)
    function ICatRepository.GetAll = GetAllCats;
    function IDogRepository.GetAll = GetAllDogs;
  public
    function GetAllCats(items: TList<TCat>; out errMsg: string): Boolean;
    function GetAllDogs(items: TList<TDog>; out errMsg: string): Boolean;
  end;

The additional GetAll declarations don't just replace the generic one, but add another method to the interface instead.

Related