Skip to content

Commit 8239a64

Browse files
committed
SourceGenerator方法排序问题修复
1 parent b578651 commit 8239a64

File tree

7 files changed

+116
-23
lines changed

7 files changed

+116
-23
lines changed

Directory.Build.props

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project>
22
<PropertyGroup>
3-
<Version>2.0.2</Version>
4-
<Copyright>Copyright © laojiu 2017-2021</Copyright>
3+
<Version>2.0.3</Version>
4+
<Copyright>Copyright © laojiu 2017-2022</Copyright>
55
<NoWarn>IDE0057</NoWarn>
66
</PropertyGroup>
77

WebApiClientCore.Analyzers.SourceGenerator/HttpApiCodeBuilder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ private string BuildMethod(IMethodSymbol method, int index)
154154
var parametersString = string.Join(",", method.Parameters.Select(item => $"{item.Type} {item.Name}"));
155155
var parameterNamesString = string.Join(",", method.Parameters.Select(item => item.Name));
156156

157-
builder.AppendLine($"\t\t[ApiMethodIndex({index})]");
157+
builder.AppendLine($"\t\t[HttpApiProxyMethod({index})]");
158158
builder.AppendLine($"\t\tpublic {method.ReturnType} {method.Name}( {parametersString} )");
159159
builder.AppendLine("\t\t{");
160160
builder.AppendLine($"\t\t\treturn ({method.ReturnType})this.{this.apiInterceptorFieldName}.Intercept(this.{this.actionInvokersFieldName}[{index}], new object[] {{ {parameterNamesString} }});");

WebApiClientCore/ApiMethodIndexAttribute.cs renamed to WebApiClientCore.Extensions.SourceGenerator/HttpApiProxyMethodAttribute.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,25 @@
11
using System;
2+
using System.ComponentModel;
23

34
namespace WebApiClientCore
45
{
56
/// <summary>
6-
/// 指示Api方法的索引特性
7-
/// 当生成代理类型使用该特性后,运行时HttpApi.FindApiMethods(Type)遵循这个方法索引
7+
/// 表示HttpApi代理方法的特性
88
/// </summary>
99
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
10-
public sealed class ApiMethodIndexAttribute : Attribute
10+
[EditorBrowsable(EditorBrowsableState.Never)]
11+
public sealed class HttpApiProxyMethodAttribute : Attribute
1112
{
1213
/// <summary>
1314
/// 获取索引值
1415
/// </summary>
1516
public int Index { get; }
1617

1718
/// <summary>
18-
/// Api方法的索引特性
19+
/// 方法的索引特性
1920
/// </summary>
2021
/// <param name="index">索引值,确保连续且不重复</param>
21-
public ApiMethodIndexAttribute(int index)
22+
public HttpApiProxyMethodAttribute(int index)
2223
{
2324
this.Index = index;
2425
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
using System;
2+
using System.Linq;
3+
using System.Reflection;
4+
5+
namespace WebApiClientCore.Implementations
6+
{
7+
/// <summary>
8+
/// 表示MethodInfo的特征
9+
/// </summary>
10+
sealed class MethodFeature : IEquatable<MethodFeature>
11+
{
12+
private readonly MethodInfo method;
13+
14+
/// <summary>
15+
/// MethodInfo的特征
16+
/// </summary>
17+
/// <param name="method"></param>
18+
public MethodFeature(MethodInfo method)
19+
{
20+
this.method = method;
21+
}
22+
23+
/// <summary>
24+
/// 比较方法原型是否相等
25+
/// </summary>
26+
/// <param name="other"></param>
27+
/// <returns></returns>
28+
public bool Equals(MethodFeature other)
29+
{
30+
var x = this.method;
31+
var y = other.method;
32+
33+
if (x.Name != y.Name || x.ReturnType != y.ReturnType)
34+
{
35+
return false;
36+
}
37+
38+
var xParameterTypes = x.GetParameters().Select(p => p.ParameterType);
39+
var yParameterTypes = y.GetParameters().Select(p => p.ParameterType);
40+
return xParameterTypes.SequenceEqual(yParameterTypes);
41+
}
42+
43+
/// <summary>
44+
/// 获取哈希
45+
/// </summary>
46+
/// <returns></returns>
47+
public override int GetHashCode()
48+
{
49+
var hashCode = new HashCode();
50+
hashCode.Add(this.method.Name);
51+
hashCode.Add(this.method.ReturnType);
52+
foreach (var parameter in this.method.GetParameters())
53+
{
54+
hashCode.Add(parameter.ParameterType);
55+
}
56+
return hashCode.ToHashCode();
57+
}
58+
}
59+
}

WebApiClientCore.Extensions.SourceGenerator/Implementations/SourceGeneratorHttpApiActivator.cs

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ namespace WebApiClientCore.Implementations
1313
/// <typeparam name="THttpApi"></typeparam>
1414
public class SourceGeneratorHttpApiActivator<THttpApi> : HttpApiActivator<THttpApi>
1515
{
16+
/// <summary>
17+
/// 代理类型
18+
/// </summary>
19+
private static readonly Type? proxyType = FindProxyTypeFromAssembly();
20+
1621
/// <summary>
1722
/// 通过查找类型代理类型创建实例
1823
/// </summary>
@@ -25,30 +30,54 @@ public SourceGeneratorHttpApiActivator(IApiActionDescriptorProvider apiActionDes
2530
{
2631
}
2732

33+
/// <summary>
34+
/// 查找接口的Api方法
35+
/// 用于创建代理对象的ApiActionInvoker
36+
/// </summary>
37+
/// <returns></returns>
38+
protected override MethodInfo[] FindApiMethods()
39+
{
40+
if (proxyType != null)
41+
{
42+
var apiMethods = base.FindApiMethods();
43+
var proxyMethods = proxyType.GetMethods();
44+
var methods = from a in apiMethods
45+
join p in proxyMethods
46+
on new MethodFeature(a) equals new MethodFeature(p)
47+
let attr = p.GetCustomAttribute<HttpApiProxyMethodAttribute>()
48+
let index = attr == null ? 0 : attr.Index
49+
orderby index
50+
select a;
51+
52+
return methods.ToArray();
53+
}
54+
55+
return base.FindApiMethods();
56+
}
57+
2858
/// <summary>
2959
/// 创建实例工厂
3060
/// </summary>
3161
/// <exception cref="ProxyTypeCreateException"></exception>
3262
/// <returns></returns>
3363
protected override Func<IHttpApiInterceptor, ApiActionInvoker[], THttpApi> CreateFactory()
3464
{
35-
var proxyType = FindProxyType(typeof(THttpApi));
3665
if (proxyType != null)
3766
{
3867
return LambdaUtil.CreateCtorFunc<IHttpApiInterceptor, ApiActionInvoker[], THttpApi>(proxyType);
3968
}
4069

4170
var message = $"找不到{typeof(THttpApi)}的代理类:{GetErrorReason()}";
4271
throw new ProxyTypeCreateException(typeof(THttpApi), message);
43-
}
72+
}
4473

4574
/// <summary>
4675
/// 从接口所在程序集查找代理类
47-
/// </summary>
48-
/// <param name="interfaceType">接口类型</param>
76+
/// </summary>
4977
/// <returns></returns>
50-
private static Type? FindProxyType(Type interfaceType)
78+
private static Type? FindProxyTypeFromAssembly()
5179
{
80+
var interfaceType = typeof(THttpApi);
5281
var httpApiType = interfaceType.IsGenericType
5382
? interfaceType.GetGenericTypeDefinition()
5483
: interfaceType;

WebApiClientCore/HttpApi.cs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,6 @@ public static MethodInfo[] FindApiMethods(Type httpApiType)
102102
.Append(httpApiType)
103103
.SelectMany(item => item.GetMethods())
104104
.Select(item => item.EnsureApiMethod())
105-
.OrderBy(item => item.Index)
106-
.Select(item => item.Method)
107105
.ToArray();
108106
}
109107

@@ -112,7 +110,7 @@ public static MethodInfo[] FindApiMethods(Type httpApiType)
112110
/// </summary>
113111
/// <exception cref="NotSupportedException"></exception>
114112
/// <returns></returns>
115-
private static (MethodInfo Method, int Index) EnsureApiMethod(this MethodInfo method)
113+
private static MethodInfo EnsureApiMethod(this MethodInfo method)
116114
{
117115
if (method.IsGenericMethod == true)
118116
{
@@ -138,10 +136,7 @@ private static (MethodInfo Method, int Index) EnsureApiMethod(this MethodInfo me
138136
throw new NotSupportedException(message);
139137
}
140138
}
141-
142-
var indexAttribute = method.GetCustomAttribute<ApiMethodIndexAttribute>();
143-
var index = indexAttribute == null ? 0 : indexAttribute.Index;
144-
return (method, index);
139+
return method;
145140
}
146141

147142
/// <summary>

WebApiClientCore/Implementations/HttpApiActivator.cs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,17 +34,26 @@ public abstract class HttpApiActivator<THttpApi> : IHttpApiActivator<THttpApi>
3434
/// <exception cref="NotSupportedException"></exception>
3535
public HttpApiActivator(IApiActionDescriptorProvider actionDescriptorProvider, IApiActionInvokerProvider actionInvokerProvider)
3636
{
37-
var interfaceType = typeof(THttpApi);
38-
this.ApiMethods = HttpApi.FindApiMethods(interfaceType);
37+
this.ApiMethods = this.FindApiMethods();
3938
this.actionInvokers = this.ApiMethods
40-
.Select(item => actionDescriptorProvider.CreateActionDescriptor(item, interfaceType))
39+
.Select(item => actionDescriptorProvider.CreateActionDescriptor(item, typeof(THttpApi)))
4140
.Select(item => actionInvokerProvider.CreateActionInvoker(item))
4241
.ToArray();
4342

4443
// 最后一步创建工厂
4544
this.factory = this.CreateFactory();
4645
}
4746

47+
/// <summary>
48+
/// 查找接口的Api方法
49+
/// 用于创建代理对象的ApiActionInvoker
50+
/// </summary>
51+
/// <returns></returns>
52+
protected virtual MethodInfo[] FindApiMethods()
53+
{
54+
return HttpApi.FindApiMethods(typeof(THttpApi));
55+
}
56+
4857
/// <summary>
4958
/// 创建实例工厂
5059
/// </summary>

0 commit comments

Comments
 (0)