gpt4 book ai didi

c# - autofac:使用不同的依赖项多次注册同一个类

转载 作者:行者123 更新时间:2023-11-30 22:00:03 25 4
gpt4 key购买 nike

给定以下层次结构:
我需要解决 ProducerRepository 的一个实例 每注册IParser IEnumerable<ISourceRepository<IDatum>> 时的依赖 已解决。

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注册,因为它会锁定每个依赖项并更改实现。如果那是唯一的方法,我会接受答案。 我希望有一种通用的方法来注册所有可能的实现

最佳答案

如果我们减少问题,您希望:

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必须有超过 1 个 Pouet 的注册同样的事情 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 , 应该可以自动化这些丑陋的注册,但它会非常复杂而且效率不高。

另一个解决方案是使用 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 会发生什么? (我没试过)?等等

关于c# - autofac:使用不同的依赖项多次注册同一个类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28827284/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com