简体   繁体   English

自动解析界面 <T> 实施 <T> 在StructureMap中(仅由通用类型T不同)

[英]Automatically resolve Interface<T> to Implementation<T> in StructureMap (differ only by generic type T)

I have an interface ( IRepository<T> ) that is currently being extended for each specific repository, ie: IUserRepository : IRepository<User> . 我有一个接口( IRepository<T> ),当前正在为每个特定的存储库进行扩展,即: IUserRepository : IRepository<User>

Each of these interfaces has corresponding concrete classes, ie: UserRepository : Repository<User>, IUserRepository . 每个接口都有相应的具体类,即: UserRepository : Repository<User>, IUserRepository

These individual repositories don't add any additional functionality, they are all empty interfaces/classes that are used simply to pass the generics around. 这些单独的存储库不添加任何其他功能,它们都是空接口/类,仅用于传递泛型。

I use StructureMap to resolve IUserRepository into UserRepository using a Registry with an assembly scanner and some naming conventions. 我用StructureMap解决IUserRepositoryUserRepository使用注册表与组装扫描仪和一些命名约定。

I'd like this to move to a way more optimised state, where instead of passing around instances of IUserRepository and getting it resolved to UserRepository , I can pass around IRepository<User> and have it resolved to Repository<User> . 我希望这可以转向更优化的状态,而不是传递IUserRepository实例并将其解析为UserRepository ,我可以传递IRepository<User>并将其解析为Repository<User>

This would remove the need to create these extra empty interfaces and classes. 这将消除创建这些额外的空接口和类的需要。

I can't work out a way to use StructureMap's configuration to setup this generic mapping. 我无法找到一种方法来使用StructureMap的配置来设置这种通用映射。 Something like this: 像这样的东西:

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

Edit 编辑

After getting the first couple of answers, I want to clarify this a bit more. 得到前几个答案之后,我想再澄清一下这个问题。

I don't want to create individual classes for the For bit of the configuration. 我不想为配置的For位创建单独的类。 I want to have the following classes/interfaces in my code: 我希望在我的代码中有以下类/接口:

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

And have the following mappings achieved with convention: 并按照惯例实现以下映射:

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

But I do not want to have to create a mapping for each one, ala: 但我不想为每个人创建一个映射,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>>();

I want a single mapping that will work for any IRepository: 我想要一个适用于任何IRepository的映射:

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

I would then use this to inject the repositories into services: 然后我会使用它将存储库注入服务:

public MyService(IRepository<User> userRepository)

And expect that to be resolved to a Repository<User> at runtime. 并希望在运行时将其解析为Repository<User>

Turns out there is no fancy method to call, or no fancy wiring to do, you just use For and Use (the non generic versions): 事实证明没有花哨的方法来调用,或者没有花哨的布线,只需使用ForUse (非泛型版本):

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

When I inject a IRepository<Person> it is being resolved as a Repository<Person> now. 当我注入IRepository<Person>它现在被解析为Repository<Person>

I encountered error 104 saying Repository wasn't pluggable for IRepository. 我遇到错误104,说Repository不能插入IRepository。 This was because Repository was marked abstract . 这是因为Repository被标记为abstract Making it non-abstract fixed that error and it is working as desired. 使它成为非抽象的,修复了错误并且它正在按预期工作。

I suggest you to take a look at the AddAllTypesOf method. 我建议你看一下AddAllTypesOf方法。 I had some similar code and achieved my objectives by using it (and kept the auto register feature working). 我有一些类似的代码,并通过使用它来实现我的目标(并保持自动注册功能工作)。

In your case, you should just change 在你的情况下,你应该改变

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

to

AddAllTypesOf(typeof(IRepository<>));

In the end, your container will be similar to: 最后,您的容器将类似于:

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

Here is an example. 这是一个例子。 Structure map will allow you to do both also. 结构图也允许您同时执行这两项操作。

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

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

Then it is useful to ask for the types by just knowing the generic type at runtime: 然后通过在运行时知道泛型类型来询问类型是有用的:

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

Have a look at IRegistrationConvention interface. 看看IRegistrationConvention界面。

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

Where RepositoryTypeScanner: RepositoryTypeScanner的位置:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM