#c# #asp.net-core
#c# #asp.net-core
Вопрос:
Я пытаюсь получить все общие реализации общего интерфейса и зарегистрировать все из них, используя не общий интерфейс, как показано ниже:
collection.AddSingleton(typeof(IEventDispatcher<>), typeof(EventDispatcher<>));
collection.AddSingleton(p =>
{
return p.GetServices(typeof(IEventDispatcher<>)).Select(x => x as IEventDispatcher);
});
public interface IEventDispatcher
{
Task HandleAsync();
}
public interface IEventDispatcher<in T> : IEventDispatcher where T : IEvent<T>
{
void Dispatch(T value);
}
Причина, по которой я это делаю, заключается в том, что мне нужны все диспетчеры событий, введенные в фоновый запуск задания, который не знает общих параметров.
public class EventJobRunner : IBackgroundJob
{
private readonly IEnumerable<IEventDispatcher> _queueHandlers;
public EventJobRunner(IEnumerable<IEventDispatcher> queueHandlers)
{
_queueHandlers = queueHandlers;
}
public TimeSpan Interval => TimeSpan.FromSeconds(10);
public async Task PerformAsync(CancellationToken cancellationToken)
{
var tasks = _queueHandlers.Select(x => x.HandleAsync());
await Task.WhenAll(tasks);
}
public void Dispose()
{
}
}
Я понимаю, что извлечение открытых обобщений так, как я это делаю, невозможно, но я не могу найти правильное решение этой простой проблемы.
Есть ли какой-либо способ реорганизовать мой код, чтобы сделать это возможным?
Ответ №1:
Я нашел решение, которое отлично работает, даже если это не самое динамичное решение.
Учитывая, что у меня есть набор классов IEvent, я уверен, что количество IEventDispacher должно быть таким же, как и экземпляров IEvent. Итак, у меня есть один диспетчер для каждого типа события. Поэтому я мог бы просто получить все реализации IEvent и добавить все соответствующие диспетчеры для каждой из них. Код можно найти ниже.
var eventTypes = TypeUtility.GetImplementationsOfGeneric(Assembly.GetExecutingAssembly(), typeof(IEvent<>));
foreach (var eventType in eventTypes)
{
var instanceType = typeof(EventDispatcher<>).MakeGenericType(eventType);
var interfaceType = typeof(IEventDispatcher<>).MakeGenericType(eventType);
collection.AddSingleton(interfaceType, instanceType);
collection.AddSingleton(typeof(IEventDispatcher), p => p.GetRequiredService(interfaceType));
}
GetImplementationsOfGeneric
это просто вспомогательный метод, который поможет мне получить все реализации интерфейса IEvent. Ниже также можно найти реализацию.
public static IEnumerable<TypeInfo> GetImplementationsOfGeneric<TInterface>(Assembly assembly)
{
var interfaceType = typeof(TInterface);
if (!interfaceType.IsGenericType)
throw new InternalException($"Type: {interfaceType.FullName} should be a generic interface.");
var types = assembly
.DefinedTypes
.Where(x => x.GetInterfaces()
.Any(i => i.IsGenericType amp;amp;
i.GetGenericTypeDefinition() == interfaceType)
amp;amp; !x.IsAbstract amp;amp; !x.IsInterface);
return types;
}
Используя этот подход, я теперь могу делегировать заводской вызов из не общего экземпляра в общий экземпляр.