@@ -20,7 +20,7 @@ public static class ITcpSocketClientExtensions
2020 /// Sends the specified string content to the connected TCP socket client asynchronously.
2121 /// </summary>
2222 /// <remarks>This method converts the provided string content into a byte array using the specified
23- /// encoding (or UTF-8 by default) and sends it to the connected TCP socket client. Ensure the client is connected
23+ /// encoding (or UTF-8 by default) and sends it to the connected TCP socket client. Ensure the client is connected
2424 /// before calling this method.</remarks>
2525 /// <param name="client">The TCP socket client to which the content will be sent. Cannot be <see langword="null"/>.</param>
2626 /// <param name="content">The string content to send. Cannot be <see langword="null"/> or empty.</param>
@@ -51,7 +51,7 @@ public static ValueTask<bool> ConnectAsync(this ITcpSocketClient client, string
5151 return client . ConnectAsync ( endPoint , token ) ;
5252 }
5353
54- private static readonly Dictionary < ITcpSocketClient , List < ( IDataPackageAdapter Adapter , Func < ReadOnlyMemory < byte > , ValueTask > Callback ) > > _cache = [ ] ;
54+ private static readonly Dictionary < ITcpSocketClient , List < ( IDataPackageAdapter Adapter , Func < ReadOnlyMemory < byte > , ValueTask > Callback ) > > Cache = [ ] ;
5555
5656 /// <summary>
5757 /// 增加 <see cref="ITcpSocketClient"/> 数据适配器及其对应的回调方法
@@ -61,25 +61,25 @@ public static ValueTask<bool> ConnectAsync(this ITcpSocketClient client, string
6161 /// <param name="callback"></param>
6262 public static void AddDataPackageAdapter ( this ITcpSocketClient client , IDataPackageAdapter adapter , Func < ReadOnlyMemory < byte > , ValueTask > callback )
6363 {
64- if ( _cache . TryGetValue ( client , out var list ) )
64+ async ValueTask ReceivedCallback ( ReadOnlyMemory < byte > buffer )
6565 {
66- list . Add ( ( adapter , cb ) ) ;
66+ // 将接收到的数据传递给 DataPackageAdapter 进行数据处理合规数据触发 ReceivedCallBack 回调
67+ await adapter . HandlerAsync ( buffer ) ;
68+ }
69+
70+ if ( Cache . TryGetValue ( client , out var list ) )
71+ {
72+ list . Add ( ( adapter , ReceivedCallback ) ) ;
6773 }
6874 else
6975 {
70- _cache . Add ( client , [ ( adapter , cb ) ] ) ;
76+ Cache . Add ( client , [ ( adapter , ReceivedCallback ) ] ) ;
7177 }
7278
73- client . ReceivedCallBack += cb ;
79+ client . ReceivedCallBack += ReceivedCallback ;
7480
7581 // 设置 DataPackageAdapter 的回调函数
7682 adapter . ReceivedCallBack = callback ;
77-
78- async ValueTask cb ( ReadOnlyMemory < byte > buffer )
79- {
80- // 将接收到的数据传递给 DataPackageAdapter 进行数据处理合规数据触发 ReceivedCallBack 回调
81- await adapter . HandlerAsync ( buffer ) ;
82- }
8383 }
8484
8585 /// <summary>
@@ -89,7 +89,7 @@ async ValueTask cb(ReadOnlyMemory<byte> buffer)
8989 /// <param name="callback"></param>
9090 public static void RemoveDataPackageAdapter ( this ITcpSocketClient client , Func < ReadOnlyMemory < byte > , ValueTask > callback )
9191 {
92- if ( _cache . TryGetValue ( client , out var list ) )
92+ if ( Cache . TryGetValue ( client , out var list ) )
9393 {
9494 var items = list . Where ( i => i . Adapter . ReceivedCallBack == callback ) . ToList ( ) ;
9595 foreach ( var c in items )
@@ -101,55 +101,21 @@ public static void RemoveDataPackageAdapter(this ITcpSocketClient client, Func<R
101101 }
102102
103103 /// <summary>
104- /// Configures the specified <see cref="ITcpSocketClient"/> to use the provided <see cref="IDataPackageAdapter"/>
105- /// for processing received data and sets a callback to handle processed data.
106- /// </summary>
107- /// <remarks>This method sets up a two-way data processing pipeline: <list type="bullet"> <item>
108- /// <description>The <paramref name="client"/> is configured to pass received data to the <paramref name="adapter"/>
109- /// for processing.</description> </item> <item> <description>The <paramref name="adapter"/> is configured to invoke
110- /// the provided <paramref name="callback"/> with the processed data.</description> </item> </list> Use this method
111- /// to integrate a custom data processing adapter with a TCP socket client.</remarks>
112- /// <param name="client">The <see cref="ITcpSocketClient"/> instance to configure.</param>
113- /// <param name="adapter">The <see cref="IDataPackageAdapter"/> used to process incoming data.</param>
114- /// <param name="callback">A callback function invoked with the processed data. The function receives a <see cref="ReadOnlyMemory{T}"/>
115- /// containing the processed data and returns a <see cref="ValueTask"/>.</param>
116- public static void SetDataPackageAdapter ( this ITcpSocketClient client , IDataPackageAdapter adapter , Func < ReadOnlyMemory < byte > , ValueTask > callback )
117- {
118- // 释放缓存
119- if ( _cache . TryGetValue ( client , out var list ) )
120- {
121- foreach ( var ( Adapter , Callback ) in list )
122- {
123- client . ReceivedCallBack -= Callback ;
124- }
125- list . Clear ( ) ;
126- }
127-
128- // 设置 ITcpSocketClient 的回调函数
129- client . ReceivedCallBack = async buffer =>
130- {
131- // 将接收到的数据传递给 DataPackageAdapter 进行数据处理合规数据触发 ReceivedCallBack 回调
132- await adapter . HandlerAsync ( buffer ) ;
133- } ;
134-
135- // 设置 DataPackageAdapter 的回调函数
136- adapter . ReceivedCallBack = callback ;
137- }
138-
139- /// <summary>
140- /// 通过指定 <see cref="IDataPackageHandler"/> 数据处理实例,设置数据适配器并配置回调方法
104+ /// 通过指定 <see cref="IDataPackageHandler"/> 数据处理实例,设置数据适配器并配置回调方法,切记使用 <see cref="RemoveDataPackageAdapter(ITcpSocketClient, Func{ReadOnlyMemory{byte}, ValueTask})"/> 移除数据处理委托防止内存泄露
141105 /// </summary>
142106 /// <param name="client"><see cref="ITcpSocketClient"/> 实例</param>
143107 /// <param name="handler"><see cref="IDataPackageHandler"/> 数据处理实例</param>
144108 /// <param name="callback">回调方法</param>
145- public static void SetDataPackageAdapter ( this ITcpSocketClient client , IDataPackageHandler handler , Func < ReadOnlyMemory < byte > , ValueTask > callback )
109+ public static void AddDataPackageAdapter ( this ITcpSocketClient client , IDataPackageHandler handler , Func < ReadOnlyMemory < byte > , ValueTask > callback )
146110 {
147- client . SetDataPackageAdapter ( new DataPackageAdapter ( handler ) , callback ) ;
111+ client . AddDataPackageAdapter ( new DataPackageAdapter ( handler ) , callback ) ;
148112 }
149113
114+ private static readonly Dictionary < ITcpSocketClient , List < ( Func < ReadOnlyMemory < byte > , ValueTask > ReceivedCallback , Delegate EntityCallback ) > > EntityCache = [ ] ;
115+
150116 /// <summary>
151117 /// Configures the specified <see cref="ITcpSocketClient"/> to use a data package adapter and a callback function
152- /// for processing received data.
118+ /// for processing received data. 切记使用 <see cref="RemoveDataPackageAdapter(ITcpSocketClient, Func{ReadOnlyMemory{byte}, ValueTask})"/> 移除数据处理委托防止内存泄露
153119 /// </summary>
154120 /// <remarks>This method sets up the <paramref name="client"/> to process incoming data using the
155121 /// specified <paramref name="adapter"/> and <paramref name="socketDataConverter"/>. The <paramref
@@ -159,24 +125,24 @@ public static void SetDataPackageAdapter(this ITcpSocketClient client, IDataPack
159125 /// <param name="adapter">The data package adapter responsible for handling incoming data.</param>
160126 /// <param name="socketDataConverter">The converter used to transform the received data into the specified entity type.</param>
161127 /// <param name="callback">The callback function to be invoked with the converted entity.</param>
162- public static void SetDataPackageAdapter < TEntity > ( this ITcpSocketClient client , IDataPackageAdapter adapter , IDataConverter < TEntity > socketDataConverter , Func < TEntity ? , Task > callback )
128+ public static void AddDataPackageAdapter < TEntity > ( this ITcpSocketClient client , IDataPackageAdapter adapter , IDataConverter < TEntity > socketDataConverter , Func < TEntity ? , Task > callback )
163129 {
164- // 释放缓存
165- if ( _cache . TryGetValue ( client , out var list ) )
130+ async ValueTask ReceivedCallback ( ReadOnlyMemory < byte > buffer )
166131 {
167- foreach ( var ( Adapter , Callback ) in list )
168- {
169- client . ReceivedCallBack -= Callback ;
170- }
171- list . Clear ( ) ;
132+ // 将接收到的数据传递给 DataPackageAdapter 进行数据处理合规数据触发 ReceivedCallBack 回调
133+ await adapter . HandlerAsync ( buffer ) ;
172134 }
173135
174- // 设置 ITcpSocketClient 的回调函数
175- client . ReceivedCallBack = async buffer =>
136+ if ( EntityCache . TryGetValue ( client , out var list ) )
176137 {
177- // 将接收到的数据传递给 DataPackageAdapter 进行数据处理合规数据触发 ReceivedCallBack 回调
178- await adapter . HandlerAsync ( buffer ) ;
179- } ;
138+ list . Add ( ( ReceivedCallback , callback ) ) ;
139+ }
140+ else
141+ {
142+ EntityCache . Add ( client , [ ( ReceivedCallback , callback ) ] ) ;
143+ }
144+
145+ client . ReceivedCallBack += ReceivedCallback ;
180146
181147 // 设置 DataPackageAdapter 的回调函数
182148 adapter . ReceivedCallBack = async buffer =>
@@ -191,21 +157,39 @@ public static void SetDataPackageAdapter<TEntity>(this ITcpSocketClient client,
191157 }
192158
193159 /// <summary>
194- /// 通过指定 <see cref="IDataPackageHandler"/> 数据处理实例,设置数据适配器并配置回调方法
160+ /// 移除 <see cref="ITcpSocketClient"/> 数据适配器及其对应的回调方法
161+ /// </summary>
162+ /// <param name="client"></param>
163+ /// <param name="callback"></param>
164+ public static void RemoveDataPackageAdapter < TEntity > ( this ITcpSocketClient client , Func < TEntity ? , Task > callback )
165+ {
166+ if ( EntityCache . TryGetValue ( client , out var list ) )
167+ {
168+ var items = list . Where ( i => i . EntityCallback . Equals ( callback ) ) . ToList ( ) ;
169+ foreach ( var c in items )
170+ {
171+ client . ReceivedCallBack -= c . ReceivedCallback ;
172+ list . Remove ( c ) ;
173+ }
174+ }
175+ }
176+
177+ /// <summary>
178+ /// 通过指定 <see cref="IDataPackageHandler"/> 数据处理实例,设置数据适配器并配置回调方法。切记使用 <see cref="RemoveDataPackageAdapter"/> 移除数据处理委托防止内存泄露
195179 /// </summary>
196180 /// <typeparam name="TEntity"></typeparam>
197181 /// <param name="client"></param>
198182 /// <param name="handler"></param>
199183 /// <param name="socketDataConverter"></param>
200184 /// <param name="callback"></param>
201- public static void SetDataPackageAdapter < TEntity > ( this ITcpSocketClient client , IDataPackageHandler handler , IDataConverter < TEntity > socketDataConverter , Func < TEntity ? , Task > callback )
185+ public static void AddDataPackageAdapter < TEntity > ( this ITcpSocketClient client , IDataPackageHandler handler , IDataConverter < TEntity > socketDataConverter , Func < TEntity ? , Task > callback )
202186 {
203- client . SetDataPackageAdapter ( new DataPackageAdapter ( handler ) , socketDataConverter , callback ) ;
187+ client . AddDataPackageAdapter ( new DataPackageAdapter ( handler ) , socketDataConverter , callback ) ;
204188 }
205189
206190 /// <summary>
207191 /// Configures the specified <see cref="ITcpSocketClient"/> to use a custom data package adapter and callback
208- /// function.
192+ /// function. 切记使用 <see cref="RemoveDataPackageAdapter"/> 移除数据处理委托防止内存泄露
209193 /// </summary>
210194 /// <remarks>This method sets up the <paramref name="client"/> to use the specified <paramref
211195 /// name="adapter"/> for handling incoming data. If the <typeparamref name="TEntity"/> type is decorated with a <see
@@ -216,74 +200,65 @@ public static void SetDataPackageAdapter<TEntity>(this ITcpSocketClient client,
216200 /// <param name="client">The TCP socket client to configure.</param>
217201 /// <param name="adapter">The data package adapter responsible for processing incoming data.</param>
218202 /// <param name="callback">The callback function to invoke with the processed entity of type <typeparamref name="TEntity"/>.</param>
219- public static void SetDataPackageAdapter < TEntity > ( this ITcpSocketClient client , IDataPackageAdapter adapter , Func < TEntity ? , Task > callback )
203+ public static void AddDataPackageAdapter < TEntity > ( this ITcpSocketClient client , IDataPackageAdapter adapter , Func < TEntity ? , Task > callback )
220204 {
221- // 释放缓存
222- if ( _cache . TryGetValue ( client , out var list ) )
223- {
224- foreach ( var ( Adapter , Callback ) in list )
225- {
226- client . ReceivedCallBack -= Callback ;
227- }
228- list . Clear ( ) ;
229- }
230-
231- // 设置 ITcpSocketClient 的回调函数
232- client . ReceivedCallBack = async buffer =>
205+ async ValueTask ReceivedCallback ( ReadOnlyMemory < byte > buffer )
233206 {
234207 // 将接收到的数据传递给 DataPackageAdapter 进行数据处理合规数据触发 ReceivedCallBack 回调
235208 await adapter . HandlerAsync ( buffer ) ;
236- } ;
237-
238- IDataConverter < TEntity > ? converter = null ;
209+ }
239210
240- var type = typeof ( TEntity ) ;
241- var converterType = type . GetCustomAttribute < DataTypeConverterAttribute > ( ) ;
242- if ( converterType is { Type : not null } )
211+ if ( EntityCache . TryGetValue ( client , out var list ) )
243212 {
244- // 如果类型上有 SocketDataTypeConverterAttribute 特性则使用特性中指定的转换器
245- converter = converterType . Type . CreateInstance < IDataConverter < TEntity > > ( ) ;
213+ list . Add ( ( ReceivedCallback , callback ) ) ;
246214 }
247215 else
248216 {
249- // 如果没有特性则从 ITcpSocketClient 中的服务容器获取转换器
250- converter = client . GetSocketDataConverter < TEntity > ( ) ;
217+ EntityCache . Add ( client , [ ( ReceivedCallback , callback ) ] ) ;
251218 }
252219
220+ client . ReceivedCallBack += ReceivedCallback ;
221+
222+ IDataConverter < TEntity > ? converter = null ;
223+
224+ var type = typeof ( TEntity ) ;
225+ var converterType = type . GetCustomAttribute < DataTypeConverterAttribute > ( ) ;
226+
227+ // 如果类型上有 SocketDataTypeConverterAttribute 特性则使用特性中指定的转换器
228+ // 如果没有特性则从 ITcpSocketClient 中的服务容器获取转换器
229+ converter = converterType is { Type : not null }
230+ ? converterType . Type . CreateInstance < IDataConverter < TEntity > > ( )
231+ : client . GetSocketDataConverter < TEntity > ( ) ;
232+
253233 if ( converter == null )
254234 {
255- // 设置正常回调
235+ // 未设置数据转换器返回 default 值
256236 adapter . ReceivedCallBack = async buffer => await callback ( default ) ;
257237 }
258238 else
259239 {
260240 // 设置转化器
261- adapter . SetDataAdapterCallback ( converter , callback ) ;
241+ adapter . ReceivedCallBack = async buffer =>
242+ {
243+ TEntity ? ret = default ;
244+ if ( converter . TryConvertTo ( buffer , out var t ) )
245+ {
246+ ret = t ;
247+ }
248+ await callback ( ret ) ;
249+ } ;
262250 }
263251 }
264252
265253 /// <summary>
266- /// 通过指定 <see cref="IDataPackageHandler"/> 数据处理实例,设置数据适配器并配置回调方法
254+ /// 通过指定 <see cref="IDataPackageHandler"/> 数据处理实例,设置数据适配器并配置回调方法。切记使用 <see cref="RemoveDataPackageAdapter"/> 移除数据处理委托防止内存泄露
267255 /// </summary>
268256 /// <param name="client"><see cref="ITcpSocketClient"/> 实例</param>
269257 /// <param name="handler"><see cref="IDataPackageHandler"/> 数据处理实例</param>
270258 /// <param name="callback">回调方法</param>
271- public static void SetDataPackageAdapter < TEntity > ( this ITcpSocketClient client , IDataPackageHandler handler , Func < TEntity ? , Task > callback )
259+ public static void AddDataPackageAdapter < TEntity > ( this ITcpSocketClient client , IDataPackageHandler handler , Func < TEntity ? , Task > callback )
272260 {
273- client . SetDataPackageAdapter ( new DataPackageAdapter ( handler ) , callback ) ;
274- }
275-
276- private static void SetDataAdapterCallback < TEntity > ( this IDataPackageAdapter adapter , IDataConverter < TEntity > converter , Func < TEntity ? , Task > callback )
277- {
278- adapter . ReceivedCallBack = async buffer =>
279- {
280- TEntity ? ret = default ;
281- if ( converter . TryConvertTo ( buffer , out var t ) )
282- {
283- ret = t ;
284- }
285- await callback ( ret ) ;
286- } ;
261+ client . AddDataPackageAdapter ( new DataPackageAdapter ( handler ) , callback ) ;
287262 }
288263
289264 private static IDataConverter < TEntity > ? GetSocketDataConverter < TEntity > ( this ITcpSocketClient client )
0 commit comments