|
| 1 | +using System; |
| 2 | +using System.Collections.Generic; |
| 3 | +using System.Linq; |
| 4 | +using System.Reflection; |
| 5 | + |
| 6 | +namespace WebApiClientCore |
| 7 | +{ |
| 8 | + /// <summary> |
| 9 | + /// HttpApi的方法查找器 |
| 10 | + /// </summary> |
| 11 | + static class HttpApiMethodFinder |
| 12 | + { |
| 13 | + /// <summary> |
| 14 | + /// 查找接口类型及其继承的接口的所有方法 |
| 15 | + /// </summary> |
| 16 | + /// <param name="httpApiType">接口类型</param> |
| 17 | + /// <exception cref="ArgumentException"></exception> |
| 18 | + /// <exception cref="NotSupportedException"></exception> |
| 19 | + /// <returns></returns> |
| 20 | + public static IEnumerable<MethodInfo> FindApiMethods(Type httpApiType) |
| 21 | + { |
| 22 | + var interfaces = httpApiType.GetInterfaces().Append(httpApiType); |
| 23 | + return Sort(interfaces, t => t.GetInterfaces()) |
| 24 | + .Reverse() |
| 25 | + .SelectMany(item => item.GetMethods().Select(m => new MethodFeature(m))) |
| 26 | + .Distinct() |
| 27 | + .Select(item => item.Method); |
| 28 | + } |
| 29 | + |
| 30 | + /// <summary> |
| 31 | + /// https://www.cnblogs.com/myzony/p/9201768.html |
| 32 | + /// </summary> |
| 33 | + /// <typeparam name="T"></typeparam> |
| 34 | + /// <param name="source"></param> |
| 35 | + /// <param name="getDependencies"></param> |
| 36 | + /// <returns></returns> |
| 37 | + private static IList<T> Sort<T>(IEnumerable<T> source, Func<T, IEnumerable<T>> getDependencies) |
| 38 | + { |
| 39 | + var sorted = new List<T>(); |
| 40 | + var visited = new Dictionary<T, bool>(); |
| 41 | + |
| 42 | + foreach (var item in source) |
| 43 | + { |
| 44 | + Visit(item, getDependencies, sorted, visited); |
| 45 | + } |
| 46 | + |
| 47 | + return sorted; |
| 48 | + } |
| 49 | + |
| 50 | + private static void Visit<T>(T item, Func<T, IEnumerable<T>> getDependencies, List<T> sorted, Dictionary<T, bool> visited) |
| 51 | + { |
| 52 | + bool inProcess; |
| 53 | + var alreadyVisited = visited.TryGetValue(item, out inProcess); |
| 54 | + |
| 55 | + // 如果已经访问该顶点,则直接返回 |
| 56 | + if (alreadyVisited) |
| 57 | + { |
| 58 | + // 如果处理的为当前节点,则说明存在循环引用 |
| 59 | + if (inProcess) |
| 60 | + { |
| 61 | + throw new ArgumentException("Cyclic dependency found."); |
| 62 | + } |
| 63 | + } |
| 64 | + else |
| 65 | + { |
| 66 | + // 正在处理当前顶点 |
| 67 | + visited[item] = true; |
| 68 | + |
| 69 | + // 获得所有依赖项 |
| 70 | + var dependencies = getDependencies(item); |
| 71 | + // 如果依赖项集合不为空,遍历访问其依赖节点 |
| 72 | + if (dependencies != null) |
| 73 | + { |
| 74 | + foreach (var dependency in dependencies) |
| 75 | + { |
| 76 | + // 递归遍历访问 |
| 77 | + Visit(dependency, getDependencies, sorted, visited); |
| 78 | + } |
| 79 | + } |
| 80 | + |
| 81 | + // 处理完成置为 false |
| 82 | + visited[item] = false; |
| 83 | + sorted.Add(item); |
| 84 | + } |
| 85 | + } |
| 86 | + |
| 87 | + /// <summary> |
| 88 | + /// 表示MethodInfo的特征 |
| 89 | + /// </summary> |
| 90 | + private class MethodFeature : IEquatable<MethodFeature> |
| 91 | + { |
| 92 | + private readonly MethodInfo method; |
| 93 | + |
| 94 | + public MethodInfo Method => method; |
| 95 | + |
| 96 | + /// <summary> |
| 97 | + /// MethodInfo的特征 |
| 98 | + /// </summary> |
| 99 | + /// <param name="method"></param> |
| 100 | + public MethodFeature(MethodInfo method) |
| 101 | + { |
| 102 | + this.method = method; |
| 103 | + } |
| 104 | + |
| 105 | + /// <summary> |
| 106 | + /// 比较方法原型是否相等 |
| 107 | + /// </summary> |
| 108 | + /// <param name="other"></param> |
| 109 | + /// <returns></returns> |
| 110 | + public bool Equals(MethodFeature other) |
| 111 | + { |
| 112 | + var x = this.method; |
| 113 | + var y = other.method; |
| 114 | + |
| 115 | + if (x.Name != y.Name || x.ReturnType != y.ReturnType) |
| 116 | + { |
| 117 | + return false; |
| 118 | + } |
| 119 | + |
| 120 | + var xParameterTypes = x.GetParameters().Select(p => p.ParameterType); |
| 121 | + var yParameterTypes = y.GetParameters().Select(p => p.ParameterType); |
| 122 | + return xParameterTypes.SequenceEqual(yParameterTypes); |
| 123 | + } |
| 124 | + |
| 125 | + /// <summary> |
| 126 | + /// 获取哈希 |
| 127 | + /// </summary> |
| 128 | + /// <returns></returns> |
| 129 | + public override int GetHashCode() |
| 130 | + { |
| 131 | + var hashCode = new HashCode(); |
| 132 | + hashCode.Add(this.method.Name); |
| 133 | + hashCode.Add(this.method.ReturnType); |
| 134 | + foreach (var parameter in this.method.GetParameters()) |
| 135 | + { |
| 136 | + hashCode.Add(parameter.ParameterType); |
| 137 | + } |
| 138 | + return hashCode.ToHashCode(); |
| 139 | + } |
| 140 | + |
| 141 | + public override bool Equals(object obj) |
| 142 | + { |
| 143 | + return obj is MethodFeature other && this.Equals(other); |
| 144 | + } |
| 145 | + } |
| 146 | + } |
| 147 | +} |
0 commit comments