我正在try 制作定制的OpenApiSchema生成器.

如何运作:

以下是示例接口:

[ApiCommands]                 
abstract public class Commands
{
    [ApiArgument( typeof( SubjectsListArguments ), isOptional: true )]
    [ApiReturn( typeof( SubjectsListResponse ) )]                     
    [Title]                                                           
    [Description]                                                     
    public const string SubjectsList = "subjects_list";               
}

因此,ApiArgument、ApiReturn代表DTO.我所需要的就是通过这个模型创建OpenApiSchema.让我们看看获得IDictionary<string, OpenApiSchema>的代码:

private IDictionary<string, OpenApiSchema> GenerateProperties(Type arguments)
{                                                                              
    var properties = new Dictionary<string, OpenApiSchema>();                  
                                                                              
    GeneratePropertiesRecursive(arguments, properties);                      
                                                                               
    return properties;                                                         
}                                                                              
private void GeneratePropertiesRecursive(                                                                        
    Type type,                                                                                                   
    IDictionary<string, OpenApiSchema> properties)                                                              
{                                                                                                                
    if (type == null) return;                                                                                                  
                                                                                                                 
    var propertyInfos = type.GetProperties();                                                                    
                                                                                                                 
    foreach (var propertyInfo in propertyInfos)                                                                
    {                                                                                                            
        var attributeValue = propertyInfo                                                                        
            .GetCustomAttribute<JsonPropertyAttribute>();                                                        
                                                                                                                 
        if (attributeValue == null)                                                                            
            continue;                                                                                            
                                                                                                                 
        var propertyName = attributeValue.PropertyName;                                                          
        var propertyType = propertyInfo.PropertyType;                                                            
                                                                                                                 
        var propertySchema = new OpenApiSchema();                                                                
                                                                                                                 
        if (propertyType.IsClass && !_excludedTypes.Contains(propertyType))                                                        
        {                                                                                                        
            if (ImplementsEnumerableTypes(propertyType, out var genericTypes))                               
            {                                                                                                    
                var itemsSchema = new OpenApiSchema();                                                           
                                                                                                                 
                foreach (var genericType in genericTypes)                                                      
                {                                                                                                
                    if (_excludedTypes.Contains(genericType))                                                
                    {                                                                                            
                        itemsSchema = genericType.MapTypeToOpenApiType(propertySchema);                        
                        break;                                                                                   
                    }                                                                                            
                                                                                                                 
                    GeneratePropertiesRecursive(genericType, itemsSchema.Properties);                          
                }                                                                                                
                                                                                                                 
                propertySchema.Type = "array";                                                                   
                propertySchema.Items = itemsSchema;                                                              
                                                                                                                 
                properties.Add(propertyName, propertySchema);                                                  
                continue;                                                                                        
            }                                                                                                    
                                                                                                                 
            GeneratePropertiesRecursive(propertyType, propertySchema.Properties);                              
        }                                                                                                        
                                                                                                                 
        if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(OptionalValue<>))    
        {                                                                                                        
            var genericType = propertyType.GetGenericArguments()[0];                                           
                                                                                                                 
            GeneratePropertiesRecursive(genericType, propertySchema.Properties);                               
                                                                                                                 
            propertyType = genericType;                                                                          
        }                                                                                                        
                                                                                                                 
        if (IsNullableType(propertyType, out var nullableType))                                              
            propertyType = nullableType;                                                                         
                                                                                                                 
        if (propertyType.IsEnum)                                                                                
        {                                                                                                        
            var types = propertyType.GetOpenApiTypesFromEnumPropertyType();                                      
                                                                                                                 
            propertySchema.Type = "string";                                                                      
            propertySchema.Enum = types;                                                                         
                                                                                                                 
            properties.Add( propertyName, propertySchema );                                                      
            continue;                                                                                            
        }                                                                                                        
                                                                                                                 
        propertySchema = propertyType.MapTypeToOpenApiType(propertySchema);                                    
                                                                                                                 
        properties.Add(propertyName, propertySchema);                                                          
    }                                                                                                            
}

我有三个问题:

  1. 我可以为一个类型多次生成OpenApiSchema,我不能控制这一点,我也不知道怎么做.
  2. 我们可以循环进入dto,这就是为什么堆栈溢出异常.例如:我们有SubjectDto个和DepartmentDto个.SubjectDto引用DepartmentDto,DepartmentDto引用SubjectDto
  3. 它真的很难读...

我们还可以添加引用:

Schema = new OpenApiSchema
{
   Reference = new OpenApiReference
   {
       Id = $"{name}_response",
       Type = ReferenceType.Schema
   }
}

推荐答案

我可以帮你解决你的第二个问题,进而,你的第三个问题...

通常,您可以使用StackQueue来扁平化递归方法(根据您希望算法是宽度优先还是深度优先,请 Select 其中之一,如下所示):

  1. 将第一次调用递归方法的参数放在堆栈/队列中
  2. 在弹出第一组参数的循环内调用您的方法
  3. 不是递归地回调该方法,而是将参数推送到堆栈/队列上,以便下一次循环迭代弹出
  4. 循环,直到不再有要执行的迭代

这种方法仍然可能导致内存问题,特别是在推送到foreach内的情况下,但将比将整个新帧推送到Stack上要高效得多.

示例:

class RecursiveStructure
{
    public required string Name { get; init; }
    public required IEnumerable<RecursiveStructure> Children { get; init; }  
}

void MethodRecursion(RecursiveStructure data)
{
    Console.WriteLine($"MR {data.Name}");
    foreach (var child in data.Children)
        MethodRecursion(child);
}

void QueueRecursion(RecursiveStructure data)
{
    var queue = new Queue<RecursiveStructure>();
    queue.Enqueue(data);
    while (queue.TryDequeue(out var current))
    {
        Console.WriteLine($"QR {current.Name}");
        foreach (var child in current.Children)
            queue.Enqueue(child);
    }
}

void StackRecursion(RecursiveStructure data)
{
    var stack = new Stack<RecursiveStructure>();
    stack.Push(data);
    while (stack.TryPop(out var current))
    {
        Console.WriteLine($"SR {current.Name}");
        foreach (var child in current.Children.Reverse()) // NB we need to reverse child order or they'll be popped backwards
            stack.Push(child);
    }
}

请注意,Stack和方法递归方法产生相同的深度优先输出,而队列方法产生宽度优先的输出.

根据上面的例子,以下是您可以使用的一些小工具:

Csharp相关问答推荐

Blazor:计算值或保留为默认值

无法从具有一对多关系的C#类中使用Swagger创建记录

在命令行中使用时安装,但在单击时不会安装

"virtual"修饰符对接口成员有什么影响?

为什么Blazor值在更改后没有立即呈现?

为什么我的ASP.NET核心MVC应用程序要为HTML元素添加一些标识符?

==和Tuple对象的相等<>

在发布表单时绑定包含附加(嵌套)列表的对象列表的正确语法是什么

Azure Function应用(. NET 8)不将信息记录到应用洞察

Azure DEVOPS找不到定制的Nuget包

如何在不考虑年份的情况下判断日期时间是否在某个日期范围内?

UWP应用程序try 将打包的本机.exe文件加载为C#程序集

EFR32BG22 BLE在SPP模式下与PC(Windows 10)不连接

C#自定义验证属性未触发IsValid方法

在ASP.NET Core 8 MVC中本地化共享视图

MudBlazor Textfield已禁用,但其验证工作正常

C#无法将.csv列转换为用于JSON转换的列表

如何在Xamarin.Forms中检索PanGesture事件的位置?

我什么时候不应该在Dispose中调用EgSuppressFinalize(This)?

在Swagger中显示自定义属性的属性名称