我想修改我当前的 LetterFactory 实现,并通过调用容器来删除对 Activator.CreateInstance 的调用,以解析使用构造函数注入(inject)完全初始化的当前 Letter。我已阅读文档 here和 here ,甚至 this所以在写这篇文章时发布,但似乎没有点击。
注意事项:
1) IDocumentServicesCore 是一个聚合。
2) 所有字母都用 LetterTypeAttribute 装饰(有数百个)
3)这个LetterFactory本身是在容器中注册的。
public class LetterFactory : ILetterFactory
{
private readonly IDocumentServicesCore _documentServicesCore;
public LetterFactory(IDocumentServicesCore documentServicesCore)
{
_documentServicesCore = documentServicesCore;
}
public LetterBase Create(int letterId)
{
if (letterId <= 0)
{
throw new ArgumentOutOfRangeException(nameof(letterId));
}
List<Type> types = typeof(LetterBase).Assembly.GetTypes()
.Where(t => !t.IsAbstract && t.IsSubclassOf(typeof(LetterBase)))
.ToList();
LetterBase letter = null;
foreach(Type type in types)
{
LetterTypeAttribute attribute = type.GetCustomAttributes<LetterTypeAttribute>().First();
if (!attribute.LetterId.Contains(letterId))
{
continue;
}
letter = Activator.CreateInstance(type, _documentServicesCore) as LetterBase;
break;
}
if (letter != null)
{
return letter;
}
string message = $"Could not find a LetterBase to create for id {letterId}.";
throw new NotSupportedException(message);
}
}
更新1
问题似乎始于字母本身未注册这一事实,我如何获取从程序集中收集字母的 LINQ 代码并注册这些字母?
谢谢, 斯蒂芬
最佳答案
您正在寻找IIndex<TKey, TValue>
这是一种字典,它可以这样组成IIndex<Int32, Func<LetterBase>>
是你想要的类型。
有了这样的类型你的LetterFactory
看起来像这样:
public class LetterFactory : ILetterFactory
{
private readonly IIndex<Int32, Func<LetterBase>> _lettersFactory;
public LetterFactory(IIndex<Int32, Func<LetterBase>> lettersFactory)
{
_lettersFactory = lettersFactory;
}
public LetterBase Create(int letterId)
{
if (letterId <= 0)
{
throw new ArgumentOutOfRangeException(nameof(letterId));
}
Func<LetterBase> letterFactory = null;
if(!this._lettersFactory.tryGetValue(letterId, out letterFactory))
{
string message = $"Could not find a LetterBase to create for id {letterId}.";
throw new NotSupportedException(message);
}
Letter letter = letterFactory();
return letter;
}
}
然后你必须像这样注册你的类型:
List<Type> letterTypes = typeof(LetterBase).Assembly.GetTypes()
.Where(t => !t.IsAbstract && t.IsSubclassOf(typeof(LetterBase)))
.ToList();
foreach(Type letterType in letterTypes)
{
LetterTypeAttribute attribute = type.GetCustomAttributes<LetterTypeAttribute>()
.First();
builder.RegisterType(letterType)
.Keyed<LetterBase>(attribute.LetterId);
}
您还将使用此代码提高性能:繁重的程序集扫描只会在启动时发生一次,而不是每次调用都会发生。
顺便说一句,请注意 IIS 托管应用程序中的程序集扫描限制:http://autofaccn.readthedocs.io/en/latest/register/scanning.html#iis-hosted-web-applications
也可以直接依赖IIndex<Int32, LetterBase>
而不是 IIndex<Int32, Func<LetterBase>>
这取决于您的范围策略。
关于c# - 如何将 Autofac 容器用作抽象工厂?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50329867/