StructureMap - 如何注册和解析开放泛型类型

时间:2010-10-31 12:09:40

标签: c# repository structuremap ioc-container

public interface IRepository<T> where T : Entity
{
    void Delete(T entity);
    T[] GetAll();
    T GetById(int id);
    void SaveOrUpdate(T enity);
    void Merge(T entity);
}

public interface ITeamEmployeeRepository : IRepository<TeamEmployee>
{
    PagedList<TeamEmployee> GetPagedTeamEmployees(int pageIndex, int pageSize);
}


public class Repository<T> : IRepository<T> where T : Entity
{
    private readonly ISession _session;

    protected Repository()
    {
        _session = GetSession();
    }

    public virtual void Delete(T entity)
    {
        _session.Delete(entity);
    }

    public virtual T[] GetAll()
    {
        return _session.CreateCriteria<T>().List<T>().ToArray();
    }

    public virtual T GetById(int id)
    {
        return _session.Get<T>(id);
    }

    public virtual void SaveOrUpdate(T enity)
    {
        _session.SaveOrUpdate(enity);
    }

    public void Merge(T entity)
    {
        _session.Merge(entity);
    }

    protected ISession GetSession()
    {
        return new SessionBuilder().GetSession();
    }
}

public class TeamEmployeeRepository : Repository<TeamEmployee>, ITeamEmployeeRepository
{
    public PagedList<TeamEmployee> GetPagedTeamEmployees(int pageIndex, int pageSize)
    {
        return GetSession().QueryOver<TeamEmployee>()
            .Fetch(x => x.Employee).Eager
            .Fetch(x => x.Team).Eager
            .ToPagedList(pageIndex, pageSize);
    }
}

现在我按如下方式注册存储库:

For<ILoanedItemRepository>().Use<LoanedItemRepository>();
For<ITeamEmployeeRepository>().Use<TeamEmployeeRepository>();
For<IArticleRepository>().Use<ArticleRepository>();
For<ISalesmanRepository>().Use<SalesmanRepository>();
For<ISalesmanArticleRepository>().Use<SalesmanArticleRepository>();
For<IGoodsGroupRepository>().Use<GoodsGroupRepository>();
For<IEmployeeRepository>().Use<EmployeeRepository>();

这非常麻烦,特别是如果有新的存储库。

更容易和更好的注册将是:

For(typeof(IRepository<>)).Use(typeof(Repository<>));

但这不起作用。 StructureMap每次都说我没有为PluginFamily Core.Domain.Bases.Repositories.ITeamEmployeeRepository定义默认实例。

我在stackoverflow上搜索并找到了新的东西:

Scan(x =>
{
    x.AssemblyContainingType(typeof(TeamEmployeeRepository));
    x.AddAllTypesOf(typeof (IRepository<>));
    x.ConnectImplementationsToTypesClosing(typeof(IRepository<>));
});

但仍然是同样的错误信息。

如何使用StructureMap 2.6.1.0注册我的存储库?

4 个答案:

答案 0 :(得分:9)

我找到了解决方案。

Scan(x =>
{
    x.WithDefaultConventions();
    x.AssemblyContainingType(typeof(TeamEmployeeRepository));
    x.AddAllTypesOf(typeof(Repository<>));
    x.ConnectImplementationsToTypesClosing(typeof(IRepository<>));
});

WithDefaultConventions 是显示代码的重要部分,因为使用此设置,您可以说StructureMap使用将ITeamEmployeeRepository映射到TeamEmployeeRepository的约定。因此,StructureMap假设该类被命名为没有前缀 I 的接口名称。

答案 1 :(得分:3)

我发现这个问题谷歌搜索“structuremap resolve generic”。现有的答案很好但很复杂。对于那些寻求简单答案的人:对于接口ISome和实现类我们写一些

c.For<ISome>().Use<Some>()

而对于通用的ISome&lt; T&gt;实现类Some&lt; T&gt;我们写

c.For(typeof(ISome<>)).Use(typeof(Some<>))

这就是全部

答案 2 :(得分:-1)

我最近通过进行小型重新设计解决了类似的问题,这使得一切变得更加简单。这对你也有用。您可以尝试从设计中删除特定接口,例如ITeamEmployeeRepositoryILoanedItemRepository。我这样做的方法是使用扩展方法。这是一个例子:

public static class RepositoryExtensions
{
    public static TeamEmployee GetById(
        this IRepository<TeamEmployee> repository, int id)
    {
        return repository.Single(e => e.TeamEmployeeId == id);
    }

    public static IQueryable<Salesman> GetActiveSalesmen(
        this IRepository<ISalesmanRepository> repository)
    {
        return repository.Where(salesman => salesman.Active);
    }

    // etc
}

之后我创建了一个IRepositoryFactory,允许我创建某种类型的存储库:

public interface IRepositoryFactory
{
    IRepository<T> CreateNewRepository<T>();
}

当使用此接口时,很容易创建此工厂的实现,要求容器创建具体的Repository<T>RepositoryFactory可能如下所示:

public class RepositoryFactory : IRepositoryFactory
{
    public IRepository<T> CreateNewRepository<T>()
    {
        return ObjectFactory.GetInstance(typeof(Repository<T>));
    }
}

使用此设计,您只需通过其RepositoryFactory界面注册具体IRepositoryFactory即可完成。现在注入IRepository<ITeamEmployeeRepository>并让客户端调用IRepositoryFactory方法,而不是在旧设计中注入CreateNewRepository<T>。由于使用了扩展方法,您可以在存储库中调用特定于类型的方法。

这样做的另一个好处是,您不需要在每次实现时重新实现最初在ITeamEmployeeRepository上定义的方法。

这种设计在我的情况下非常有效,特别是因为我的IRepository<T>接口使用了表达式树。当然,我不可能看到这样的设计是否适合你,但我希望它会。

祝你好运。

答案 3 :(得分:-2)

您需要创建自己的ITypeScanner并在Scan()来电中注册。查看GenericConnectionScanner的源代码作为起点。您不必搜索类型以查看它们是否实现IRepository<T>,而是查看它们是否实现了实现IRepository<T>的任何接口,然后注册该接口的类型。

更新:所有关于IRepository<T>的讨论让我过度思考这个问题,当时它真的是一个无关紧要的细节。只需使用Rookian建议的DefaultConventions扫描程序。

相关问题