gpt4 book ai didi

c# - .NET Core 注册具有不同数量参数的原始泛型

转载 作者:行者123 更新时间:2023-11-30 17:30:48 25 4
gpt4 key购买 nike

我正在处理 .NET Core 项目。我需要为一些原始泛型自动注册一个默认值。当参数计数相同时,一切正常。

public void RegisterServiceDefaults(IServiceCollection services)
{
services.AddSingleton(typeof(IAdaptable<,>), typeof(DynamicAdapter<,>));
}

我的 IAdaptable<TEntity, TDTO>允许实体之间的动态适应,但在我的具体服务中,默认情况下我们需要一个接口(interface),以便我们可以控制每个属性如何适应,我的 IAdaptable<TEntity, TDTO>实际上只是为了方便这个接口(interface)的包装

IAdaptable<TEntity, TIDTO, TDTO>  
where TDTO: TIDTO
{
}

IAdaptable<TEntity, TDTO> : IAdaptable<TEntity, TDTO, TDTO>
{
}

如果有人请求 IAdaptable<TEntity, TDTO, TDTO>,我如何才能通用地注册我的适应性对象?它会默认返回 IAdaptable<TEntity, TDTO>

EDIT 提供用于理解问题 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当它仅用于适应时。

现在,当最终用户创建他们可以依赖任一接口(interface)的服务时,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 上实现接口(interface),或者他们可能只是使用更明确的基础并决定使用 RestService<TEntity, TIDTO, TDTO> , 在这种情况下会给他们留下一个讨厌的运行时错误。因此,为了避免让我的支持团队处理最终用户错误,我想避免这种情况并让 IAdaptable<TEntity,TIDTO, TDTO>使用我的动态适配器,它是一个 IAdaptable<TEntity,TDTO> .

最佳答案

您可以使用反射创建自己的扫描实现,以在一行中注册多种类型。

服务集合扩展

这里我们实现了一个简单的 Scan允许您选择一个接口(interface)(无论是通用的还是非通用的)的扩展方法,并且该接口(interface)的所有实现都将为所有提供的程序集注册。

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);

关于c# - .NET Core 注册具有不同数量参数的原始泛型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49087739/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com