Reputation: 103
public interface IRepository <T> where T : EntityBase
{
T FindBy(object key);
void Add(T item);
T this[object key] { get; set; }
void Remove(T item);
}
This is the code sample of a generic Repository interface which was given by the author of the book "Domain-Driven-Design .NET C#". Without explanation the author puts an indexer in the interface T this[object key] { get; set; }
where the object key is the objects ID (in terms of identity across the system). The author states that the indexer is put there for emphasizing that a repository should emulate a collection of objects in memory. So my question is: Are there any benefits in putting an indexer in an interface? Any links, videos, books, tutorials would help me a lot. Thank you.
Upvotes: 2
Views: 189
Reputation: 44600
The author states that the indexer is put there for emphasizing that a repository should emulate a collection of objects in memory.
I honestly never heard of this concept. I saw repository pattern implementation on a lot of projects and we never used indexer there. In fact indexer will serve to get item by ID, which would duplicate your T FindBy(object key);
.
So, my summary: repository in most of cases indeed provides access to a collection of objects, but I don't see any value in adding indexer to it. I'd rather focus on transactions/queries, needed for your application.
I usually implement generic IRepository<T>
with BaseRepository : IRepository<T>
and then implement specific repositories UsersRepository : BaseRepository<User>, IUsersRepository
where IUsersRepository
interface contains specifc methods for user queries and commands.
Upvotes: 1
Reputation: 64933
Are there any benefits in putting an indexer in an interface?
This is subjective. If you find more meaningful locate objects by some key, why not?
The main issue when using indexers is they can be overloaded. While your interface defines an indexer to get objects by id (where the id is object
... I would turn object id into a generic type...), following the proposed pattern, it might happen that you lose the meaning of the indexer if you define more than an indexer than the one that retrieves domain objects by their identifiers.
For example:
T this[object key] { get; set; }
T this[T someObject] { get; set; }
T this[int whoKnowsWhatIsIntegerHere] { get; set; }
At the end of the day, it's up to you to implement indexers and it won't emphasize more or less using them in terms of implementing repositories in the right way: repositories are fine when they mediate between the domain and the data mapper to translate domain objects to data and vice versa.. That is, it's not about what name have their methods or if they look like IList<T>
or not...
Working like a collection doesn't mean look like a collection...
Upvotes: 0
Reputation: 20731
The author states that the indexer is put there for emphasizing that a repository should emulate a collection of objects in memory.
This sounds like a reasonable rationale. By the word "emphasizing", it points to one important aspect: The indexer does not necessarily add any functionality, it can also be used simply to improve readability of the resulting code.
Assuming some object has a property named Resources
of type IRepository<Something>
, without the indexer, specific items can be retrieved only as follows:
var theItem = myObject.Resources.FindBy(someKey);
With an indexer, the following is possible, as well:
var theItem = myObject.Resources[someKey];
To some extent, this is a matter of personal preference, but the second version might be more intuitively recognizeable as a mere retrieval from something like a list, rather than an arbitrary parametrized method call.
Upvotes: 0
Reputation: 69260
An indexer is used in this case to retrieve an object given it's key (not its index in the collection). Out of the standard generic interfaces in System.Collections.Generic the IDictionary<TKey, TValue>
is the one that contains that functionality. However, that interface contains a lot more functionality that is not naturally exposed by a repository.
Sure, it would be possible to implement those other methods, but they would not be efficient. And offering non-efficient APIs is a sure way to invite the user of the API to write inefficient code.
Upvotes: 0