Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing multiple generic interfaces - type error

Tags:

c#

.net

generics

I'm trying to do something like this:

public interface IRepository<T>
{
  T Get<T>(int id);
}

public interface IFooBarRepository : IRepository<Foo>, IRepository<Bar>
{
}

IFooBarRepository repo = SomeMethodThatGetsTheActualClass();
Foo foo = repo.Get<Foo>(1);

I'm getting a warning:

Type parameter 'T' has the same name as the type parameter from outer type 'IRepository'

And an error:

The call is ambiguous between the following methods or properties: 'IRepository.Get(int)' and 'IRepository.Get(int)'

Any thoughts on how I can make this pattern work?

like image 885
Jonas Avatar asked Sep 23 '10 20:09

Jonas


People also ask

Can a class implement different instantiations of the same generic interface?

It is prohibited that a type implements or extends two different instantiations of the same interface. This is because the bridge method generation process cannot handle this situation.

What does the generics constraint of type interface do?

Interface Type Constraint You can constrain the generic type by interface, thereby allowing only classes that implement that interface or classes that inherit from classes that implement the interface as the type parameter. The code below constrains a class to an interface.

Can C# implement multiple interfaces?

C# allows that a single class can implement multiple interfaces at a time, and also define methods and variables in that interface.


1 Answers

To call the appropriate one, you'll need to make the compiler think of the expression in the appropriate way:

IFooBarRepository repo = SomeMethodThatGetsTheActualClass();
IRepository<Foo> fooRepo = repo;
Foo foo = fooRepo.Get(1);

Note that you could just cast it in one statement:

IFooBarRepository repo = SomeMethodThatGetsTheActualClass();
Foo foo = ((IRepository<Foo>)repo).Get(1);

... but that looks pretty ugly to me.

That deals with calling the method. Implementing both interfaces in one class is the next hurdle... because they'll have the same signature in terms of parameters. You'll have to implement at least one of them explicitly - and it might cause less confusion if you did both:

public class FooBarRepository : IFooBarRepository
{
    Foo IRepository<Foo>.Get(int id)
    {
        return new Foo();
    } 

    Bar IRepository<Bar>.Get(int id)
    {
        return new Bar();
    } 
}

EDIT: You'll also need to make Get a non-generic method: currently you're trying to redeclare the type parameter T in IRepository<T>.Get<T>; you just want to use the existing type parameter of IRepository<T>.

like image 156
Jon Skeet Avatar answered Sep 29 '22 20:09

Jon Skeet