Here's the solution I've use to solve this problem in various projects, most often around domain-driven event handlers (like IHandlerOf<DomainEvent>
) or plugin systems.
First, I specify what assemblies I want to include for type discovery.
var assemblies = RegistrationByConvention.FromSpecificAssemblies(
typeof(ClassInAssembly1).Assembly,
typeof(ClassInAssembly2).Assembly,
typeof(ClassInAssembly3).Assembly);
Then I garner all types that are not abstract, not value types, and are visible.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
public class RegistrationByConvention
{
public static IEnumerable<Type> FromSpecificAssemblies(params Assembly[] assemblies)
{
return GetTypes(assemblies);
}
private static IEnumerable<Type> GetTypes(IEnumerable<Assembly> assemblies)
{
return assemblies.SelectMany(assembly =>
{
try
{
return GetTypes(assembly.DefinedTypes);
}
catch (ReflectionTypeLoadException ex)
{
return GetTypes(ex.Types.TakeWhile(x => x != null).Select(x => x.GetTypeInfo()));
}
});
}
private static IEnumerable<Type> GetTypes(IEnumerable<TypeInfo> typeInfos)
{
return typeInfos
.Where(x => x.IsClass & !x.IsAbstract && !x.IsValueType && x.IsVisible)
.Select(ti => ti.AsType());
}
}
Finally, for generic implementations like yours, I use IsAssignableFrom
and MakeGenericType
. I'd recommend assigning a base class or interface to the UpdateWidget
and other widgets to make then discoverable.
foreach (var matchingType in assemblies.Where((type) => { return typeof(BaseWidget).IsAssignableFrom(type); }))
{
container.RegisterTypes(
assemblies.Where((type) =>
{
return typeof(ICommandService<>).MakeGenericType(matchingType).IsAssignableFrom(type);
}),
WithMappings.FromAllInterfaces,
WithName.TypeName,
WithLifetime.Transient);
}
If you just want to solve your error and use your existing code, you'll want to use Type.MakeGenericType
as in typeof(ICommandService<>).MakeGenericType(matchingType)
.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…