[英]Inject two objects of same type using autofac
我一直在嘗試使用 autofac 注冊和注入兩個相同類型的不同對象,但我無法成功注入第二個 object。 注入的第二個 object 在使用SingleInstance()時始終是第一個注冊的類型 1 的相同實例,或者在使用InstancePerLifetimeScope時是類型 1 的另一個實例。 InstancePerDependency也不起作用。 關於如何實現這一點的任何建議? 謝謝!
發現了一個類似的未解決問題 - 注入相同類型的多個實例 - Autofac
/* Register named object of type1 */
builder.RegisterType<TestClient>()
.As<TestClient>()
.UsingConstructor(typeof(Settings), typeof(SampleEnum))
.WithParameters(new[]{
new ResolvedParameter((p, c) => p.ParameterType.IsAssignableTo<Settings>(), (p, c) => c.Resolve<Settings>()),
new ResolvedParameter((p, c) => p.ParameterType == typeof(SampleEnum) && p.Name == "eventtype",(p, c) => SampleEnum.Type1),
}).Named<TestClient>(clientoftype1).InstancePerDependency();
/* Register named object of type2 */
builder.RegisterType<TestClient>()
.As<TestClient>()
.UsingConstructor(typeof(Settings), typeof(SampleEnum))
.WithParameters(new[]{
new ResolvedParameter((p, c) => p.ParameterType.IsAssignableTo<Settings>(), (p, c) => c.Resolve<Settings>()),
new ResolvedParameter((p, c) => p.ParameterType == typeof(SampleEnum) && p.Name == "eventtype",(p, c) => SampleEnum.Type2),
}).Named<TestClient>(clientoftype2)).InstancePerDependency();
/*Controller registration
public DevController(TestClient clientoftype1, TestClient clientoftype2)
{..}
*/
builder
.RegisterType<DevController>()
.As<DevController>()
.WithParameters(new []{
ResolvedParameter.ForNamed<TestClient>("clientoftype1"),
ResolvedParameter.ForNamed<TestClient>("clientoftype2"),
} ).InstancePerRequest();
/*Check registered types*/
var types = container.ComponentRegistry.Registrations
.Where(r => typeof(TestClient).IsAssignableFrom(r.Activator.LimitType))
.Select(r => r.Activator.LimitType);
var countofobjects = types.ToList();//This has 2 objects.
一般來說,你在做什么 - 在構造函數中需要多個相同類型但作為單獨的參數是一種依賴注入的禁忌。 也就是說,這通常是要避免做的事情:
public class Consumer
{
public Consumer(Dependency a, Dependency b) { /* ... */ }
}
這樣做的原因是,正如您所發現的,DI 主要適用於基於類型的注入。 這不是 .NET 或 Autofac 獨有的,就是這樣。 從設計的角度來看,我可能會問你為什么不這樣做,而是做類似......
public class Consumer
{
public Consumer(IEnumerable<Dependency> dependencies) { /* ... */ }
}
我會問,因為如果您不能將這兩個依賴項視為相同,那么這有點違反Liskov 替換原則,並且您實際上希望使用不同的接口(即使它們看起來相同)來區分這兩個東西.
public class Consumer
{
public Consumer(IDependencyA a, IDependencyB b) { /* ... */ }
}
但是,假設您無法重新設計事物,您可以使用命名服務和KeyFilterAttribute
來獲得您想要的東西。
這是一個完整的、最小的控制台應用程序,展示了它的工作原理。
using System;
using Autofac;
using Autofac.Features.AttributeFilters;
namespace AutofacDemo
{
public static class Program
{
public static void Main()
{
var builder = new ContainerBuilder();
builder.RegisterType<Consumer>().WithAttributeFiltering();
builder.RegisterType<Dependency>().SingleInstance().AsSelf().Named<Dependency>("a");
builder.RegisterType<Dependency>().SingleInstance().AsSelf().Named<Dependency>("b");
using var container = builder.Build();
var consumer = container.Resolve<Consumer>();
consumer.WriteInfo();
}
}
public class Consumer
{
private readonly Dependency _a;
private readonly Dependency _b;
public Consumer([KeyFilter("a")]Dependency a, [KeyFilter("b")] Dependency b)
{
this._a = a;
this._b = b;
}
public void WriteInfo()
{
Console.WriteLine("A: {0}", this._a.Id);
Console.WriteLine("B: {0}", this._b.Id);
}
}
public class Dependency
{
public Dependency()
{
this.Id = Guid.NewGuid();
}
public Guid Id { get; }
}
}
運行此程序時,您將獲得兩個不同的ID,例如:
A: 542f8ae9-bd04-4821-a3e5-5eb3c41bbbc6
B: cb9b8245-c12e-4928-b618-0ecbf0a75a84
如果您要刪除過濾器屬性,那么您將獲得相同的 ID,因為如您所見,按類型注入每次都會以相同的實例結束 - 最后獲勝。 過濾是讓它工作的魔法。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.