在StructureMap中自动解析Interface <t>到Implementation <t>(仅与泛型类型T不同)</t> </t>

时间:2011-01-25 01:00:27

标签: c# asp.net generics structuremap

我有一个接口(IRepository<T>),目前正在为每个特定的存储库进行扩展,即:IUserRepository : IRepository<User>

每个接口都有相应的具体类,即:UserRepository : Repository<User>, IUserRepository

这些单独的存储库不添加任何其他功能,它们都是空接口/类,仅用于传递泛型。

我使用StructureMap使用带有汇编扫描程序的注册表和一些命名约定将IUserRepository解析为UserRepository

我希望这可以转向更优化的状态,而不是传递IUserRepository的实例并将其解析为UserRepository,我可以传递IRepository<User>和已将其解析为Repository<User>

这将消除创建这些额外空接口和类的需要。

我无法找到使用StructureMap配置来设置此通用映射的方法。像这样:

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

修改

在得到前几个答案之后,我想再详细说明一下。

我不想为配置的For位创建单独的类。我想在我的代码中使用以下类/接口:

  • IRepository<T> where T : Entity
  • Repository<T> : IRepository<T> where T : Entity
  • Person : Entity
  • Product : Entity
  • Order : Entity
  • Whatever : Entity

使用约定实现以下映射:

IRepository<Person> => Repository<Person>
IRepository<Product> => Repository<Product>
IRepository<Order> => Repository<Order>
IRepository<Whatever> => Repository<Whatever>

但我想要为每个人创建一个映射,ala:

For<IRepository<Person>>().Use<Repository<Person>>();
For<IRepository<Product>>().Use<Repository<Product>>();
For<IRepository<Order>>().Use<Repository<Order>>();
For<IRepository<Whatever>>().Use<Repository<Whatever>>();

我想要一个适用于任何IRepository的映射:

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

然后我会使用它将存储库注入服务:

public MyService(IRepository<User> userRepository)

并期望在运行时将其解析为Repository<User>

5 个答案:

答案 0 :(得分:24)

原来没有花哨的方法可以调用,或者没有花哨的布线,只需使用ForUse(非通用版本):

public class DataRegistry : Registry
{
    public DataRegistry()
    {
        For(typeof (IRepository<>)).Use(typeof(Repository<>));
    }
}

当我注入IRepository<Person>时,它现在被解析为Repository<Person>

我遇到错误104,说Repository不能插入IRepository。这是因为存储库标记为abstract。使它成为非抽象的,修复了错误并且它正在按预期工作。

答案 1 :(得分:6)

我建议你看一下AddAllTypesOf方法。我有一些类似的代码并通过使用它来实现我的目标(并保持自动注册功能正常工作)。

在你的情况下,你应该改变

For<IRepository<Person>>().Use<Repository<Person>>();
For<IRepository<Product>>().Use<Repository<Product>>();
For<IRepository<Order>>().Use<Repository<Order>>();
For<IRepository<Whatever>>().Use<Repository<Whatever>>();

AddAllTypesOf(typeof(IRepository<>));

最后,您的容器将类似于:

return new Container(x =>
        {
            x.Scan(y =>
            {
                y.TheCallingAssembly();
                y.AddAllTypesOf(typeof(IRepository<>));
                y.WithDefaultConventions();
            });
        });

答案 2 :(得分:1)

这是一个例子。结构图也允许你同时做这两件事。

 //IRepository
 For<IMemberRepository>().Add<MemberRepository>();

 //IRepository<T>
 For<IRepository<Member>>().Add<MemberRepository>();

然后通过在运行时知道泛型类型来询问类型是很有用的:

Type repositoryType = typeof(IRepository<>).MakeGenericType(modelType);
IocResolve.Resolve(repositoryType);

答案 3 :(得分:1)

答案 4 :(得分:0)

查看IRegistrationConvention界面。

public class DomainRegistry : Registry
{
    public DomainRegistry()
        : base()
    {
        Scan(y =>
        {
            y.AssemblyContainingType<IRepository>();
            y.Assembly(Assembly.GetExecutingAssembly().FullName);
            y.With(new RepositoryTypeScanner());
        });

RepositoryTypeScanner:

public class RepositoryTypeScanner : IRegistrationConvention
{
    public void Process(Type type, Registry registry)
    {
      ...