我正在研究.NET核心项目。我需要自动注册一些原始泛型的默认值。当参数计数相同时一切正常。
public void RegisterServiceDefaults(IServiceCollection services)
{
services.AddSingleton(typeof(IAdaptable<,>), typeof(DynamicAdapter<,>));
}
我的IAdaptable<TEntity, TDTO>
工程允许实体之间的动态适应,但在我的具体服务默认情况下我们期望一个接口,所以我们可以控制每个属性的适应方式,我的IAdaptable<TEntity, TDTO>
实际上只是一个方便的包装器在这个界面
IAdaptable<TEntity, TIDTO, TDTO>
where TDTO: TIDTO
{
}
IAdaptable<TEntity, TDTO> : IAdaptable<TEntity, TDTO, TDTO>
{
}
我怎么能一般注册我的适应表,以便如果有人要求IAdaptable<TEntity, TDTO, TDTO>
它将默认返回IAdaptable<TEntity, TDTO>
?
编辑提供了解问题TL; DR
这被用于提供两种注册方式的休息框架,最终用户可以创建一个IAdaptable<TEntity, TIDTO, TDTO>
示例适配器可能如下所示:
public UserAdapter : IAdaptable<User, IUserDTO, UserDTO>, IUserDTO
{
User _user;
public UserAdapter(User user)
{
this._user = user;
}
public int Id
{
get => this._user.Id;
set { /*Do nothing you cannot override the server Id*/}
}
//... The rest of the User Properties
}
当最终用户创建服务时,他们可以使用IAdaptable<TEntity, TIDTO, TDTO>
,或者如果他们不想创建具体的服务,他们可以将一些选项传递给只知道TEntity
和TDTO
属性的动态属性,没有理由创建一个TIDTO
,它只用于适应。
现在,当最终用户创建服务时,他们可以依赖任一接口,默认情况下GenericBase服务请求IAdaptable,如下所示:
public class RestService<TEntity, TIDTO, TDTO>
where TDTO: TIDTO
{
public RestService(DbContext context, IAdaptable<TEntity, TIDTO, TDTO> adapter, IValidator<TEntity> validator)
{
}
}
并为简化版本:
public class RestService<TEntity, TDTO> : RestService<TEntity, TDTO, TDTO>
{
//Implementation...
}
现在一般来说,如果最终用户想要一个动态适配器,他们应该使用简化的RestService
,但根据他们的架构,他们可能在DTO上实现接口,或者他们只是使用更明确的基础并决定使用RestService<TEntity, TIDTO, TDTO>
,其中case会给他们带来一个讨厌的运行时错误。因此,为了避免我的支持团队处理最终用户错误,我想避免这种情况,并让IAdaptable<TEntity,TIDTO, TDTO>
使用我的动态适配器,这是一个IAdaptable<TEntity,TDTO>
。
您可以使用Reflection创建自己的扫描实现,以使用单行注册多个类型。
在这里,我们实现了一个简单的Scan
扩展方法,允许您选择一个接口(无论是通用的还是非泛型的),并且将为所有提供的程序集注册该接口的所有实现。
public static class ServiceCollectionExtensions
{
public static IServiceCollection Scan(
this IServiceCollection serviceCollection,
Assembly assembly,
Type serviceType,
ServiceLifetime lifetime)
{
return Scan(serviceCollection, new Assembly[] { assembly }, serviceType, lifetime);
}
public static IServiceCollection Scan(
this IServiceCollection serviceCollection,
IEnumerable<Assembly> assemblies,
Type interfaceType,
ServiceLifetime lifetime)
{
foreach (var type in assemblies.SelectMany(x =>
x.GetTypes().Where(t => t.IsClass && !t.IsAbstract)))
{
foreach (var i in type.GetInterfaces())
{
// Check for generic
if (i.IsGenericType && i.GetGenericTypeDefinition() == interfaceType)
{
var genericInterfaceType = interfaceType.MakeGenericType(i.GetGenericArguments());
serviceCollection.Add(new ServiceDescriptor(genericInterfaceType, type, lifetime));
}
// Check for non-generic
else if (!i.IsGenericType && i == interfaceType)
{
serviceCollection.Add(new ServiceDescriptor(interfaceType, type, lifetime));
}
}
}
return serviceCollection;
}
// TODO: Add overloads ScanTransient, ScanSingleton, etc that call the
// above with the corresponding lifetime argument
}
要注册关闭通用IAdaptable<,,>
类型的所有类型并将它们注册为单例,您只需要使用:
services.Scan(
assembly: typeof(User).Assembly,
interfaceType: typeof(IAdaptable<,,>),
lifetime: ServiceLifetime.Singleton);