150 lines
4.6 KiB
C#
150 lines
4.6 KiB
C#
using System.Collections.ObjectModel;
|
||
|
||
namespace LinkToolAddin.common;
|
||
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using System.Reflection;
|
||
using System.Text.Json;
|
||
|
||
public static class JsonSchemaGenerator
|
||
{
|
||
public static string GenerateJsonSchema(MethodInfo methodInfo)
|
||
{
|
||
var parameters = methodInfo.GetParameters();
|
||
var properties = new Dictionary<string, object>();
|
||
var required = new List<string>();
|
||
|
||
foreach (var param in parameters)
|
||
{
|
||
var paramName = param.Name ?? throw new InvalidOperationException("参数没有名称。");
|
||
var paramSchema = GenerateSchemaForType(param.ParameterType);
|
||
properties[paramName] = paramSchema;
|
||
|
||
if (!param.IsOptional)
|
||
{
|
||
required.Add(paramName);
|
||
}
|
||
}
|
||
|
||
var schemaRoot = new Dictionary<string, object>
|
||
{
|
||
{ "$schema", "http://json-schema.org/draft-07/schema#" },
|
||
{ "type", "object" },
|
||
{ "properties", properties }
|
||
};
|
||
|
||
if (required.Count > 0)
|
||
{
|
||
schemaRoot["required"] = required;
|
||
}
|
||
|
||
var options = new JsonSerializerOptions { WriteIndented = true };
|
||
return JsonSerializer.Serialize(schemaRoot, options);
|
||
}
|
||
|
||
private static object GenerateSchemaForType(Type type)
|
||
{
|
||
// 处理可空类型
|
||
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
|
||
{
|
||
var underlyingType = Nullable.GetUnderlyingType(type);
|
||
return new[] { GenerateSchemaForType(underlyingType), "null" };
|
||
}
|
||
|
||
// 处理集合类型(数组或IEnumerable<T>)
|
||
if (IsCollectionType(type, out Type elementType))
|
||
{
|
||
return new Dictionary<string, object>
|
||
{
|
||
{ "type", "array" },
|
||
{ "items", GenerateSchemaForType(elementType) }
|
||
};
|
||
}
|
||
|
||
// 处理基本类型(int, string, bool, etc.)
|
||
if (IsPrimitiveType(type))
|
||
{
|
||
string jsonType = MapClrTypeToJsonType(type);
|
||
var schema = new Dictionary<string, object> { { "type", jsonType } };
|
||
|
||
if (type == typeof(DateTime))
|
||
schema["format"] = "date-time";
|
||
else if (type == typeof(Guid))
|
||
schema["format"] = "uuid";
|
||
|
||
return schema;
|
||
}
|
||
|
||
// 处理复杂类型(类、结构体)
|
||
if (type.IsClass || type.IsValueType)
|
||
{
|
||
var props = new Dictionary<string, object>();
|
||
foreach (var prop in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
|
||
{
|
||
props[prop.Name] = GenerateSchemaForType(prop.PropertyType);
|
||
}
|
||
|
||
return new Dictionary<string, object>
|
||
{
|
||
{ "type", "object" },
|
||
{ "properties", props }
|
||
};
|
||
}
|
||
|
||
// 默认情况
|
||
return new Dictionary<string, object> { { "type", "any" } };
|
||
}
|
||
|
||
private static bool IsCollectionType(Type type, out Type elementType)
|
||
{
|
||
if (type == typeof(string))
|
||
{
|
||
elementType = null;
|
||
return false;
|
||
}
|
||
|
||
if (type.IsArray)
|
||
{
|
||
elementType = type.GetElementType();
|
||
return true;
|
||
}
|
||
|
||
if (type.IsGenericType)
|
||
{
|
||
var genericTypeDef = type.GetGenericTypeDefinition();
|
||
if (genericTypeDef == typeof(IEnumerable<>) ||
|
||
genericTypeDef == typeof(List<>) ||
|
||
genericTypeDef == typeof(Collection<>))
|
||
{
|
||
elementType = type.GetGenericArguments()[0];
|
||
return true;
|
||
}
|
||
}
|
||
|
||
elementType = null;
|
||
return false;
|
||
}
|
||
|
||
private static bool IsPrimitiveType(Type type)
|
||
{
|
||
return type.IsPrimitive || type == typeof(string) || type == typeof(decimal) || type == typeof(DateTime) || type == typeof(Guid);
|
||
}
|
||
|
||
private static string MapClrTypeToJsonType(Type type)
|
||
{
|
||
if (type == typeof(int) || type == typeof(short) || type == typeof(long) ||
|
||
type == typeof(uint) || type == typeof(ushort) || type == typeof(ulong))
|
||
return "integer";
|
||
if (type == typeof(float) || type == typeof(double) || type == typeof(decimal))
|
||
return "number";
|
||
if (type == typeof(bool))
|
||
return "boolean";
|
||
if (type == typeof(string))
|
||
return "string";
|
||
if (type == typeof(DateTime) || type == typeof(Guid))
|
||
return "string";
|
||
return "any";
|
||
}
|
||
} |