-
Notifications
You must be signed in to change notification settings - Fork 446
/
Copy pathHttpApi.cs
164 lines (146 loc) · 5.23 KB
/
HttpApi.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
using System;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using WebApiClientCore.Internals;
namespace WebApiClientCore
{
/// <summary>
/// 提供HttpApi命名获取和方法获取等功能
/// </summary>
public static class HttpApi
{
/// <summary>
/// 获取接口的名称
/// 该名称可用于接口对应的OptionsName
/// </summary>
/// <param name="httpApiType">接口类型</param>
/// <returns></returns>
public static string GetName(Type? httpApiType)
{
return GetName(httpApiType, includeNamespace: true);
}
/// <summary>
/// 获取接口的名称
/// </summary>
/// <param name="httpApiType">接口类型</param>
/// <param name="includeNamespace">是否包含命名空间</param>
/// <returns></returns>
public static string GetName(Type? httpApiType, bool includeNamespace)
{
if (httpApiType == null)
{
return string.Empty;
}
var builder = new ValueStringBuilder(stackalloc char[256]);
if (includeNamespace == true)
{
builder.Append(httpApiType.Namespace);
builder.Append(".");
}
GetName(httpApiType, ref builder);
return builder.ToString();
}
/// <summary>
/// 获取类型的短名称
/// </summary>
/// <param name="type">类型</param>
/// <param name="builder"></param>
/// <returns></returns>
private static void GetName(Type type, ref ValueStringBuilder builder)
{
if (type.IsGenericType == false)
{
builder.Append(type.Name);
return;
}
var name = type.Name.AsSpan();
var index = name.LastIndexOf('`');
if (index > -1)
{
name = name[..index];
}
builder.Append(name);
builder.Append('<');
var i = 0;
var arguments = type.GetGenericArguments();
foreach (var argument in arguments)
{
GetName(argument, ref builder);
if (++i < arguments.Length)
{
builder.Append(',');
}
}
builder.Append('>');
}
/// <summary>
/// 查找接口类型及其继承的接口的所有方法
/// </summary>
/// <param name="httpApiType">接口类型</param>
/// <exception cref="ArgumentException"></exception>
/// <exception cref="NotSupportedException"></exception>
/// <returns></returns>
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070", Justification = "已使用DynamicallyAccessedMembers.All关联接口的父接口成员")]
public static MethodInfo[] FindApiMethods([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type httpApiType)
{
if (httpApiType.IsInterface == false)
{
throw new ArgumentException(Resx.required_InterfaceType.Format(httpApiType.Name));
}
return httpApiType.GetInterfaces().Append(httpApiType)
.SelectMany(item => item.GetMethods())
.Select(item => item.EnsureApiMethod())
.ToArray();
}
/// <summary>
/// 确保方法是支持的Api接口
/// </summary>
/// <exception cref="NotSupportedException"></exception>
/// <returns></returns>
private static MethodInfo EnsureApiMethod(this MethodInfo method)
{
if (method.IsGenericMethod == true)
{
throw new NotSupportedException(Resx.unsupported_GenericMethod.Format(method));
}
if (method.IsSpecialName == true)
{
throw new NotSupportedException(Resx.unsupported_Property.Format(method));
}
if (method.IsTaskReturn() == false)
{
var message = Resx.unsupported_ReturnType.Format(method);
throw new NotSupportedException(message);
}
foreach (var parameter in method.GetParameters())
{
if (parameter.ParameterType.IsByRef == true)
{
var message = Resx.unsupported_ByRef.Format(parameter);
throw new NotSupportedException(message);
}
}
return method;
}
/// <summary>
/// 检测方法是否为Task或ITask返回值
/// </summary>
/// <param name="method"></param>
/// <returns></returns>
private static bool IsTaskReturn(this MethodInfo method)
{
if (method.ReturnType.IsInheritFrom<Task>())
{
return true;
}
if (method.ReturnType.IsGenericType == false)
{
return false;
}
var taskType = method.ReturnType.GetGenericTypeDefinition();
return taskType == typeof(ITask<>);
}
}
}