编辑 正如 Steven 在评论中所解释的,ContractClass 和 ContractClassFor 标有 [Conditional("CONTRACTS_FULL")],此解决方案可能会为这些属性引入错误。请参阅 Steven 的评论以获得更好的解释。
我不知道任何允许对RegisterAssemblyTypes 方法注册的注册进行全局过滤的机制。使用此方法过滤注册的唯一解决方案是使用代码示例中所示的Where 方法。
当注册在ComponentRegistry 中注册时,无法将其从注册表中删除。
如果您不想在每次注册时使用Where 方法,您可以创建另一个方法。
public static class ContractClassRegistrationExtensions
{
public static IRegistrationBuilder<TLimit, TScanningActivatorData, TRegistrationStyle> NotContractClass<TLimit, TScanningActivatorData, TRegistrationStyle>(this IRegistrationBuilder<TLimit, TScanningActivatorData, TRegistrationStyle> registration) where TScanningActivatorData : ScanningActivatorData
{
if (registration == null)
{
throw new ArgumentNullException("registration");
}
return registration.Where(t => t.GetCustomAttribute<ContractClassForAttribute>() == null);
}
}
使用这种方法,而不是
builder.RegisterAssemblyTypes(ThisAssembly)
.Where(t=> t.GetCustomAttribute<ContractClassForAttribute>() == null)
.As<IFoo>();
你会写:
builder.RegisterAssemblyTypes(ThisAssembly)
.NotContractClass()
.As<IFoo>();
这不是一个真正的解决方案,但它是我在类似情况下会使用的解决方案。
顺便说一句,如果你真的想要使用 Autofac 的魔法,你可以实现一个IRegistrationSource
public class FilterRegistrationSource : IRegistrationSource
{
private static MethodInfo _createFilteredRegistrationMethod = typeof(FilterRegistrationSource).GetMethod("CreateFilteredRegistration");
public Boolean IsAdapterForIndividualComponents
{
get
{
return false;
}
}
public IEnumerable<IComponentRegistration> RegistrationsFor(Service service, Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor)
{
IServiceWithType serviceWithType = service as IServiceWithType;
if (serviceWithType == null)
{
yield break;
}
Type serviceType = serviceWithType.ServiceType;
if (!serviceType.IsClosedTypeOf(typeof(IEnumerable<>)))
{
yield break;
}
Type elementType = new Type[] { serviceType }.Concat(serviceType.GetInterfaces())
.Where(t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IEnumerable<>))
.Select(t => t.GetGenericArguments()[0])
.First();
yield return (IComponentRegistration)FilterRegistrationSource._createFilteredRegistrationMethod.MakeGenericMethod(elementType)
.Invoke(this, new Object[] { serviceWithType });
}
public IComponentRegistration CreateFilteredRegistration<T>(IServiceWithType serviceWithType)
{
return RegistrationBuilder.ForDelegate((cc, p) => cc.ComponentRegistry
.RegistrationsFor(serviceWithType.ChangeType(typeof(T)))
.Where(r => !r.Activator.LimitType.GetCustomAttributes(typeof(ContractClassForAttribute), false).Any())
.Select(r => r.Activator.ActivateInstance(cc, p))
.Cast<T>())
.As((Service)serviceWithType)
.CreateRegistration();
}
}
你可以这样注册:builder.RegisterSource(new FilterRegistrationSource())
我没有测试过此解决方案的性能损失,请谨慎使用。
另一个有趣的解决方案是使用 AOP 自定义注册注册的方式。