-
Notifications
You must be signed in to change notification settings - Fork 446
/
Copy pathJsonPatchDocument~.cs
179 lines (163 loc) · 5.94 KB
/
JsonPatchDocument~.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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
using System;
using System.Collections.Concurrent;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace WebApiClientCore.Parameters
{
/// <summary>
/// 表示将自身作为JsonPatch请求内容
/// </summary>
/// <typeparam name="T"></typeparam>
public class JsonPatchDocument<T> : JsonPatchDocument where T : class
{
/// <summary>
/// 命名策略
/// </summary>
private readonly JsonNamingPolicy? namingPolicy;
/// <summary>
/// 将自身作为JsonPatch请求内容
/// 使用CamelCase命名
/// </summary>
public JsonPatchDocument()
: this(JsonNamingPolicy.CamelCase)
{
}
/// <summary>
/// 将自身作为JsonPatch请求内容
/// </summary>
/// <param name="namingPolicy">命名策略</param>
public JsonPatchDocument(JsonNamingPolicy? namingPolicy)
{
this.namingPolicy = namingPolicy;
}
/// <summary>
/// Replace操作
/// </summary>
/// <typeparam name="TField"></typeparam>
/// <param name="pathSelector">path选择器</param>
/// <param name="value">替换成的值</param>
/// <exception cref="ArgumentNullException"></exception>
public void Replace<TField>(Expression<Func<T, TField>> pathSelector, TField value)
{
var path = this.GetExpressionPath(pathSelector);
base.Replace(path, value);
}
/// <summary>
/// Remove操作
/// </summary>
/// <typeparam name="TField"></typeparam>
/// <param name="pathSelector">path选择器</param>
/// <exception cref="ArgumentNullException"></exception>
public void Remove<TField>(Expression<Func<T, TField>> pathSelector)
{
var path = this.GetExpressionPath(pathSelector);
base.Remove(path);
}
/// <summary>
/// 返回表示式对应的path
/// </summary>
/// <param name="pathSelector">path选择器</param>
/// <returns></returns>
private string GetExpressionPath(LambdaExpression pathSelector)
{
var visitor = new PathVisitor(pathSelector, this.GetMemberName);
return visitor.ToString();
}
/// <summary>
/// 返回成员的名称
/// </summary>
/// <param name="member">成员</param>
/// <returns></returns>
protected virtual string GetMemberName(MemberInfo member)
{
var jsonProperty = member.GetCustomAttribute<JsonPropertyNameAttribute>();
if (jsonProperty != null && string.IsNullOrEmpty(jsonProperty.Name) == false)
{
return jsonProperty.Name;
}
if (this.namingPolicy == null)
{
return member.Name;
}
return this.namingPolicy.ConvertName(member.Name);
}
/// <summary>
/// 表示Path访问器
/// </summary>
private class PathVisitor : ExpressionVisitor
{
/// <summary>
/// 成员名称委托
/// </summary>
private readonly Func<MemberInfo, string> nameFunc;
/// <summary>
/// path变量
/// </summary>
private readonly StringBuilder path = new();
/// <summary>
/// 属性名称缓存
/// </summary>
private static readonly ConcurrentDictionary<MemberInfo, string> staticNameCache = new();
/// <summary>
/// Path访问器
/// </summary>
/// <param name="pathSelector">表达式</param>
/// <param name="nameFunc">成员名称委托</param>
/// <exception cref="ArgumentNullException"></exception>
public PathVisitor(LambdaExpression pathSelector, Func<MemberInfo, string> nameFunc)
{
if (pathSelector == null)
{
throw new ArgumentNullException(nameof(pathSelector));
}
this.nameFunc = nameFunc;
base.Visit(pathSelector.Body);
}
/// <summary>
/// 访问成员时
/// </summary>
/// <param name="node"></param>
/// <returns></returns>
protected override Expression VisitMember(MemberExpression node)
{
var name = staticNameCache.GetOrAdd(node.Member, this.nameFunc);
this.path.Insert(0, $"/{name}");
return base.VisitMember(node);
}
/// <summary>
/// 访问二元表达式
/// </summary>
/// <param name="node"></param>
/// <returns></returns>
protected override Expression VisitBinary(BinaryExpression node)
{
if (node.NodeType == ExpressionType.ArrayIndex)
{
if (node.Right.NodeType != ExpressionType.Constant)
{
var index = Expression.Lambda<Func<int>>(node.Right).Compile().Invoke();
var expression = node.Update(node.Left, node.Conversion, Expression.Constant(index));
return base.Visit(expression);
}
else
{
var index = ((ConstantExpression)node.Right).Value;
this.path.Insert(0, $"/{index}");
}
}
return base.VisitBinary(node);
}
/// <summary>
/// 转换为字符串
/// </summary>
/// <returns></returns>
public override string ToString()
{
return this.path.ToString();
}
}
}
}