Implementing multiple common interfaces - type error

I am 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 get a warning:

The type parameter "T" has the same name as the type parameter from the external type "IRepository"

And the 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 template work?

+4
source share
5 answers

To call the appropriate one, you need to make the compiler think about the expression accordingly:

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

Note that you can simply write it in a single expression:

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

... but it looks pretty ugly to me.

This refers to a method call. Implementing both interfaces in the same class is the next obstacle ... because they will have the same signature in terms of parameters. You will have to implement at least one of them explicitly - and this can cause less confusion if you both did:

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

EDIT: you also need to make Get not a generic method: you are currently trying to override a parameter of type T in IRepository<T>.Get<T> ; you just want to use an existing parameter of type IRepository<T> .

+7
source

Sorry, you can’t. This is not how generics are designed to work in C #. If you go with this template, you will always have to eliminate which version of the interface you want to call Get() by pressing repo :

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

which is probably not the one you want.

You could, of course, implement proxy methods in the implementation of IFooBarRepository that return the correct types ... but again, this may not be what you are looking for.

However, you can create properties on IFooBarRepository that improve the syntax:

 interface IFooBarRepository : IRepository<Foo>, IRepository<Bar> { IRepository<Foo> FooGetter { get; } IRepository<Bar> BarGetter { get; } } 

Now you can write:

 IFooBarRepository repo = SomeMethodThatGetsTheActualClass(); Foo foo = repo.FooGetter.Get(1); Bar bar = repo.BarGetter.Get(2); 

In general, it is advisable to avoid common methods that do not accept type parameters of type parameters as formal arguments. In your case, you are trying to code the semantics of the repositories directly into the type system. Perhaps you should separate this responsibility from the type that expresses the behavior of the repository and the separate type that expresses the behavior of the sample objects.

+2
source

You do not need to repeat T again in the method declaration. It is already declared in the interface:

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

Also note that you need to explicitly implement the IFooBarRepository interface, because only the return type of the Get method is different, which is not possible.

+1
source

Instead:

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

using

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

What kind of general sense of using generics plays to avoid casting, but, unfortunately, what you are doing is impossible without providing additional hints to the compiler.

+1
source

Use an explicit implementation. To indicate which Get , first go to the appropriate interface.

0
source

All Articles