2015-03-03 46 views
2

考慮以下層次結構:
我需要解決的ProducerRepository每個註冊IParser依賴一個實例時IEnumerable<ISourceRepository<IDatum>>得到解決。autofac:註冊同一類不止一次與不同的相關

public class ProducerRepository : ISourceRepository<Data> 
{ 
    public ProducerRepository(IRepository repository) 
    {} 
} 

public interface ISourceRepository<out T> where T : class, IDatum 
{} 

public class Repository : IRepository 
{ 
    public Repository(IParser parser) 
    {} 
} 

public class ParserTypeOne : IParser {} 
public class ParserTypeTwo : IParser {} 

我需要註冊ProducerRepository如下。

builder.RegisterType<ProducerRepository>()   
.WithParserTypeOne() // how do I specify this as a particular dependency 
.As<ISourceRepository<IDatum>(); 

builder.RegisterType<ProducerRepository>()   
.WithParserTypeTwo() // another type of parser. 
.As<ISourceRepository<IDatum>>(); 

// OR: better still if at all possible... 
builder.RegisterType<ProducerRepository>() // one of these for each underlying dependency 
.WithEachPossibleTypeOfParser() // one for each dependency 
.As<ISourceRepository<IDatum>>(); 

我需要知道如何註冊類兩次,一次與每種類型的依賴,這樣,當一個IEnumerable<ISourceRepository<IDatum>>解決我得到ProducerRepository的一個單獨的實例爲每個不同的實現解析器。

更好的是,能夠爲在程序集掃描中找到的解析器的每個實例註冊一個單獨的ProducerRepository並添加它將會很好。

我一直希望不必更改實現來使用KeyedMeta註冊,因爲它會鎖定每個依賴項並更改實現。如果這是做到這一點的唯一方法,我會接受答案。 我希望通用的方式來註冊所有可能的實現

回答

3

如果我們減少的問題,你想的是:

public class Pouet 
{ 
    public Pouet(Foo foo) { } 
} 
public class Foo 
{ 
    public Foo(IBar bar) { } 
} 
public interface IBar { } 
public class Bar1 : IBar { } 
public class Bar2 : IBar { } 

ContainerBuilder builder = new ContainerBuilder(); 
    builder.RegisterType<Pouet>().AsSelf(); 
    builder.RegisterType<Foo>().AsSelf(); 
    builder.RegisterType<Bar1>().As<IBar>(); 
    builder.RegisterType<Bar2>().As<IBar>(); 
    IContainer container = builder.Build(); 

    IEnumerable<Pouet> pouets = container.Resolve<IEnumerable<Pouet>>(); 

    Console.WriteLine(pouets.Count()); // => must return 2 here ! 

基本上,返回超過1 Pouet使用container.Resolve<IEnumerable<Pouet>>()container必須有Pouet同樣的事情超過1個登記對於Foo。爲了做到這一點,就可以讓這個醜陋的東西:

// don't do that 
    ContainerBuilder builder = new ContainerBuilder(); 
    builder.RegisterType<Pouet>().Named<Pouet>("initial"); 
    builder.RegisterType<Foo>().Named<Foo>("initial"); 
    builder.Register(c => c.ResolveNamed<Pouet>("initial", TypedParameter.From<Foo>(c.Resolve<IEnumerable<Meta<Foo>>>().Where(m => (Int32)m.Metadata["Bar"] == 1).Select(m => m.Value).First()))).As<Pouet>().WithMetadata("Bar", 1); 
    builder.Register(c => c.ResolveNamed<Pouet>("initial", TypedParameter.From<Foo>(c.Resolve<IEnumerable<Meta<Foo>>>().Where(m => (Int32)m.Metadata["Bar"] == 1).Select(m => m.Value).First()))).As<Pouet>().WithMetadata("Bar", 2); 
    builder.Register(c => c.ResolveNamed<Foo>("initial",TypedParameter.From<IBar>(c.Resolve<IEnumerable<Meta<IBar>>>().Where(m => (Int32)m.Metadata["Bar"] == 1).Select(m => m.Value).First()))).As<Foo>().WithMetadata("Bar", 1); 
    builder.Register(c => c.ResolveNamed<Foo>("initial",TypedParameter.From<IBar>(c.Resolve<IEnumerable<Meta<IBar>>>().Where(m => (Int32)m.Metadata["Bar"] == 2).Select(m => m.Value).First()))).As<Foo>().WithMetadata("Bar", 2); 
    builder.RegisterType<Bar1>().As<IBar>().WithMetadata("Bar", 1); 
    builder.RegisterType<Bar2>().As<IBar>().WithMetadata("Bar", 2); 

    IContainer container = builder.Build(); 

    IEnumerable<Pouet> pouets = container.Resolve<IEnumerable<Pouet>>(); 

    Console.WriteLine(pouets.Count()); // => 2 ! 

如果要添加新的中間依賴或新IBar,你必須編寫大量的代碼。使用自定義的IRegistrationSource,應該可以自動執行這些uglies註冊,但這將會非常複雜並且效率不高。

另一個解決方案是與lifetimeScope玩:

ContainerBuilder builder = new ContainerBuilder(); 
    builder.RegisterType<Pouet>().AsSelf(); 
    builder.RegisterType<Foo>().AsSelf(); 
    builder.RegisterType<Bar1>().As<IBar>(); 
    builder.RegisterType<Bar2>().As<IBar>(); 

    IContainer container = builder.Build(); 

    using (ILifetimeScope workScope = container.BeginLifetimeScope()) 
    { 
     List<Pouet> pouets = new List<Pouet>(); 

     foreach (IComponentRegistration registration in container.ComponentRegistry.RegistrationsFor(new TypedService(typeof(IBar)))) 
     { 
      using (ILifetimeScope scope = container.BeginLifetimeScope(cb => cb.RegisterComponent(registration))) 
      { 
       Pouet pouet = scope.Resolve<Pouet>(); 
       workScope.Disposer.AddInstanceForDisposal(scope); 
       pouets.Add(pouet); 
      } 
     } 

     Console.WriteLine(pouets.Count); 
    } 

通過這個代碼可以在IRegistrationSource內部使用的方式,所以你應該能夠在您的容器上解決IEnumerable<Pouet>()

如果可能的話,我會建議重構你的代碼,使其更簡單,玩來自另一個ILifetimeScope的實例可能會有問題,我對這些實例的處置沒有真正的信心:如果類型被註冊爲InstancePerLifetimeScope(我沒試過)?等等。

+0

非常感謝您的詳細回覆。我已經開始爲這些服務進行明確的註冊。感謝您的提示。 – Jim 2015-03-03 19:01:49

相關問題