Вы ищете 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>>
, это зависит от вашей стратегии охвата.