Search code examples
c#genericsinterfacerepositorystructuremap

Connecting different implementations with StructureMap


I have a pretty straightforward generic repository:

public interface IRepository<TEntity, TNotFound>
    where TEntity : EntityObject
    where TNotFound : TEntity, new()
{
    IList<TEntity> GetAll();
    TEntity With(int id);
    TEntity Persist(TEntity itemToPersist);
    void Delete(TEntity itemToDelete);
}

I want to define a contract for a repository for the type Term without any special behaviour. So it looks like this:

public class TermNotFound : Term
{ public TermNotFound() : base(String.Empty, String.Empty) { } }


public interface ITermRepository : IRepository<Term, TermNotFound> { }

Now for testing, I want to create an in-memory implementation of the generic repo, so I have this (not finished for brevity):

public class InMemoryRepository<TEntity, TNotFound> : IRepository<TEntity, TNotFound>
    where TEntity : EntityObject
    where TNotFound : TEntity, new()
{
    private IList<TEntity> _repo = new List<TEntity>();


    public IList<TEntity> GetAll()
    {
        return this._repo;
    }

    public TEntity With(int id)
    {
        return this._repo.SingleOrDefault(i => i.Id == id) ?? new TNotFound();
    }

    public TEntity Persist(TEntity itemToPersist)
    {
        throw new NotImplementedException();
    }

    public void Delete(TEntity itemToDelete)
    {
        throw new NotImplementedException();
    }
}

It's not hard to see how I want it to work. For my tests, I want the generic InMemoryRepository implementation to be injected to create my ITermRepository.

Well, I can't get StructureMap to do it. I have tried using WithDefaultConventions and ConnectImplementationsToTypesClosing(typeof(IRepository<,>)) in the scanner without success. What can I try next?


Solution

  • Your InMemoryRepository doesn't implement ITermRepository interface. That's why you can't connect them.

    The best thing you could do with what you have is injecting InMemoryRepository<Term, TermNotFound> for IRepository<Term, TermNotFound>.

    If you really need to inject ITermRepository, then you'll need to have another repository class inheriting from InMemoryRepository and implementing ITermRepository:

    public class InMemoryTermRepository 
        : InMemoryRepository<Term, TermNotFound>, ITermRepository
    {
    }
    

    Now you can connect ITermRepository to InMemoryTermRepository using:

    .For<ITermRepository>().Use<InMemoryTermRepository>()
    

    If you have many interfaces like ITermRepository, you could create a StructureMap convention, to connect I...Repository to InMemory...Repository. The default convention is to connect IClass to Class.