尝试使用源生成器规范NodeModel代码逻辑

This commit is contained in:
fengjiayi
2024-10-20 12:10:57 +08:00
parent 9931fa7436
commit e38833a58c
127 changed files with 5173 additions and 1839 deletions

View File

@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Serein.Library.Network.WebSocketCommunication.Handle
{
/// <summary>
/// 表示参数可以为空(Net462不能使用NutNull的情况
/// </summary>
public sealed class NeedfulAttribute : Attribute
{
}
}

View File

@@ -4,7 +4,9 @@ using Serein.Library.Utils;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
@@ -20,53 +22,164 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
/// </summary>
public class JsonMsgHandleConfig
{
private readonly Delegate EmitDelegate;
private readonly EmitHelper.EmitMethodType EmitMethodType;
public Guid HandleGuid { get; }
private Action<Exception, Action<object>> OnExceptionTracking;
internal JsonMsgHandleConfig(SocketHandleModel model,ISocketHandleModule instance, MethodInfo methodInfo, Action<Exception, Action<object>> onExceptionTracking)
internal JsonMsgHandleConfig(SocketHandleModule model,
ISocketHandleModule instance,
MethodInfo methodInfo,
Action<Exception, Action<object>> onExceptionTracking,
bool ArgNotNull)
{
EmitMethodType = EmitHelper.CreateDynamicMethod(methodInfo,out EmitDelegate);
this.Model = model;
this.Module = model;
Instance = instance;
var parameterInfos = methodInfo.GetParameters();
ParameterType = parameterInfos.Select(t => t.ParameterType).ToArray();
ParameterName = parameterInfos.Select(t => t.Name).ToArray();
this.ParameterType = parameterInfos.Select(t => t.ParameterType).ToArray();
this.ParameterName = parameterInfos.Select(t => t.Name).ToArray();
this.HandleGuid = instance.HandleGuid;
this.OnExceptionTracking = onExceptionTracking;
this.ArgNotNull = ArgNotNull;
this.useMsgData = parameterInfos.Select(p => p.GetCustomAttribute<UseMsgDataAttribute>() != null).ToArray();
#if NET5_0_OR_GREATER
this.IsCheckArgNotNull = parameterInfos.Select(p => p.GetCustomAttribute<NotNullAttribute>() != null).ToArray();
#endif
if(IsCheckArgNotNull is null)
{
IsCheckArgNotNull = parameterInfos.Select(p => p.GetCustomAttribute<NeedfulAttribute>() != null).ToArray();
}
else
{
// 兼容两种非空特性的写法
var argNotNull = parameterInfos.Select(p => p.GetCustomAttribute<NeedfulAttribute>() != null).ToArray();
for (int i = 0; i < IsCheckArgNotNull.Length; i++)
{
if (!IsCheckArgNotNull[i] && argNotNull[i])
{
IsCheckArgNotNull[i] = true;
}
}
}
}
private SocketHandleModel Model;
private ISocketHandleModule Instance;
public Guid HandleGuid { get; }
private string[] ParameterName;
private Type[] ParameterType;
/// <summary>
/// 参数不能为空
/// </summary>
private bool ArgNotNull;
/// <summary>
/// Emit委托
/// </summary>
private readonly Delegate EmitDelegate;
/// <summary>
/// Emit委托类型
/// </summary>
private readonly EmitHelper.EmitMethodType EmitMethodType;
/// <summary>
/// 未捕获的异常跟踪
/// </summary>
private readonly Action<Exception, Action<object>> OnExceptionTracking;
/// <summary>
/// 所在的模块
/// </summary>
private readonly SocketHandleModule Module;
/// <summary>
/// 所使用的实例
/// </summary>
private readonly ISocketHandleModule Instance;
/// <summary>
/// 参数名称
/// </summary>
private readonly string[] ParameterName;
/// <summary>
/// 参数类型
/// </summary>
private readonly Type[] ParameterType;
/// <summary>
/// 是否使用整体data参数
/// </summary>
private readonly bool[] useMsgData;
/// <summary>
/// 是否检查变量为空
/// </summary>
private readonly bool[] IsCheckArgNotNull;
public async void Handle(Func<string, Task> RecoverAsync, JObject jsonObject)
public async void Handle(Func<object, Task> SendAsync, JObject jsonObject)
{
object[] args = new object[ParameterType.Length];
bool isCanInvoke = true;; // 表示是否可以调用方法
for (int i = 0; i < ParameterType.Length; i++)
{
var type = ParameterType[i];
var argName = ParameterName[i];
if (type.IsGenericType)
if (useMsgData[i])
{
if (type.IsAssignableFrom(typeof(Func<object, Task>)))
args[i] = jsonObject.ToObject(type);
}
else if (type.IsValueType)
{
var jsonValue = jsonObject.GetValue(argName);
if (!(jsonValue is null))
{
args[i] = jsonValue.ToObject(type);
}
else
{
if (ArgNotNull && !IsCheckArgNotNull[i]) // 检查不能为空
{
args[i] = Activator.CreateInstance(type); // 值类型返回默认值
}
else
{
isCanInvoke = false; // 参数不能为空,终止调用
break;
}
}
}
else if (type.IsClass)
{
var jsonValue = jsonObject.GetValue(argName);
if (!(jsonValue is null))
{
args[i] = jsonValue.ToObject(type);
}
else
{
if (ArgNotNull && !IsCheckArgNotNull[i])
{
args[i] = null; // 引用类型返回null
}
else
{
isCanInvoke = false; // 参数不能为空,终止调用
break;
}
}
}
else if (type.IsGenericType) // 传递SendAsync委托
{
if (type.IsAssignableFrom(typeof(Func<object, Task>)))
{
args[i] = new Func<object, Task>(async data =>
{
var jsonText = JsonConvert.SerializeObject(data);
await RecoverAsync.Invoke(jsonText);
await SendAsync.Invoke(jsonText);
});
}
else if (type.IsAssignableFrom(typeof(Func<string, Task>)))
{
args[i] = new Func<string, Task>(async data =>
{
await RecoverAsync.Invoke(data);
await SendAsync.Invoke(data);
});
}
else if (type.IsAssignableFrom(typeof(Action<object>)))
@@ -74,7 +187,7 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
args[i] = new Action<object>(async data =>
{
var jsonText = JsonConvert.SerializeObject(data);
await RecoverAsync.Invoke(jsonText);
await SendAsync.Invoke(jsonText);
});
}
else if (type.IsAssignableFrom(typeof(Action<string>)))
@@ -82,28 +195,17 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
args[i] = new Action<string>(async data =>
{
var jsonText = JsonConvert.SerializeObject(data);
await RecoverAsync.Invoke(jsonText);
await SendAsync.Invoke(jsonText);
});
}
}
else if (type.IsValueType || type.IsClass)
{
var jsonValue = jsonObject.GetValue(argName);
if (jsonValue is null)
{
// 值类型返回默认值引用类型返回null
args[i] = type.IsValueType ? Activator.CreateInstance(type) : null;
}
else
{
args[i] = jsonValue.ToObject(type);
}
}
}
}
//Stopwatch sw = new Stopwatch();
//sw.Start();
if (!isCanInvoke)
{
return;
}
object result;
try
{
@@ -133,27 +235,21 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
{
var jsonText = JsonConvert.SerializeObject(data);
await RecoverAsync.Invoke(jsonText);
await SendAsync.Invoke(jsonText);
}));
}
//sw.Stop();
//Console.WriteLine($"Emit Invoke{sw.ElapsedTicks * 1000000F / Stopwatch.Frequency:n3}μs");
if(Model.IsReturnValue && result != null && result.GetType().IsClass)
if(Module.IsReturnValue && result != null && result.GetType().IsClass)
{
var reusltJsonText = JsonConvert.SerializeObject(result);
_ = RecoverAsync.Invoke($"{reusltJsonText}");
//var reusltJsonText = JsonConvert.SerializeObject(result);
_ = SendAsync.Invoke(result);
//_ = SendAsync.Invoke($"{reusltJsonText}");
}
}
public void Clear()
{
Instance = null;
ParameterName = null;
ParameterType = null;
//expressionDelegate = null;
}
}

View File

@@ -1,9 +1,12 @@
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Serein.Library.Network.WebSocketCommunication.Handle
@@ -37,13 +40,21 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
/// </summary>
public ConcurrentDictionary<string, JsonMsgHandleConfig> MyHandleConfigs = new ConcurrentDictionary<string, JsonMsgHandleConfig>();
internal void AddHandleConfigs(SocketHandleModel model, ISocketHandleModule instance, MethodInfo methodInfo
, Action<Exception, Action<object>> onExceptionTracking)
/// <summary>
/// 添加处理配置
/// </summary>
/// <param name="module">处理模块</param>
/// <param name="jsonMsgHandleConfig">处理配置</param>
internal bool AddHandleConfigs(SocketHandleModule module,JsonMsgHandleConfig jsonMsgHandleConfig)
{
if (!MyHandleConfigs.ContainsKey(model.ThemeValue))
if (!MyHandleConfigs.ContainsKey(module.ThemeValue))
{
var jsonMsgHandleConfig = new JsonMsgHandleConfig(model,instance, methodInfo, onExceptionTracking);
MyHandleConfigs[model.ThemeValue] = jsonMsgHandleConfig;
MyHandleConfigs[module.ThemeValue] = jsonMsgHandleConfig;
return true;
}
else
{
return false;
}
}
@@ -72,18 +83,14 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
{
var temp = MyHandleConfigs.Values;
MyHandleConfigs.Clear();
foreach (var config in temp)
{
config.Clear();
}
}
/// <summary>
/// 处理JSON数据
/// </summary>
/// <param name="RecoverAsync"></param>
/// <param name="tSendAsync"></param>
/// <param name="jsonObject"></param>
public void HandleSocketMsg(Func<string, Task> RecoverAsync, JObject jsonObject)
public void HandleSocketMsg(Func<string, Task> tSendAsync, JObject jsonObject)
{
// 获取到消息
string themeKeyName = jsonObject.GetValue(ThemeJsonKey)?.ToString();
@@ -92,11 +99,36 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
// 没有主题
return;
}
if (jsonObject[DataJsonKey] is JObject dataJsonObject)
Func<object, Task> SendAsync = async (data) =>
{
handldConfig.Handle(RecoverAsync, dataJsonObject);
var sendMsg = new
{
theme = themeKeyName,
token = "",
data = data,
};
var msg = JsonConvert.SerializeObject(sendMsg);
await tSendAsync(msg);
};
try
{
JObject dataObj = jsonObject.GetValue(DataJsonKey).ToObject<JObject>();
handldConfig.Handle(SendAsync, dataObj);
}
catch (Exception ex)
{
Console.WriteLine($"error in ws : {ex.Message}{Environment.NewLine}json value:{jsonObject}");
return;
}
}
}
}

View File

@@ -93,7 +93,7 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
var themeKey = moduleAttribute.ThemeKey;
var dataKey = moduleAttribute.DataKey;
var handlemodule = AddMyHandleModule(themeKey, dataKey);
var methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
.Select(method =>
@@ -101,7 +101,7 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
var methodsAttribute = method.GetCustomAttribute<AutoSocketHandleAttribute>();
if (methodsAttribute is null)
{
return (null, null);
return (null, null,false);
}
else
{
@@ -109,13 +109,14 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
{
methodsAttribute.ThemeValue = method.Name;
}
var model = new SocketHandleModel
var model = new SocketHandleModule
{
IsReturnValue = methodsAttribute.IsReturnValue,
ThemeValue = methodsAttribute.ThemeValue,
};
var value = methodsAttribute.ThemeValue;
return (model, method);
var argNotNull = methodsAttribute.ArgNotNull;
return (model, method, argNotNull);
}
})
.Where(x => !(x.model is null)).ToList();
@@ -124,14 +125,21 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
return;
}
Console.WriteLine($"add websocket handle model :");
Console.WriteLine($"theme key, data key : {themeKey}, {dataKey}");
foreach ((var model, var method) in methods)
foreach ((var module, var method,var argNotNull) in methods)
{
Console.WriteLine($"theme value : {model.ThemeValue}");
Console.WriteLine($"theme value : {module.ThemeValue}");
try
{
handlemodule.AddHandleConfigs(model, socketControlBase, method, onExceptionTracking);
var jsonMsgHandleConfig = new JsonMsgHandleConfig(module, socketControlBase, method, onExceptionTracking, argNotNull);
var result = handlemodule.AddHandleConfigs(module,jsonMsgHandleConfig);
if (!result)
{
throw new Exception("添加失败,已经添加过相同的配置");
}
}
catch (Exception ex)
{
@@ -145,17 +153,17 @@ namespace Serein.Library.Network.WebSocketCommunication.Handle
/// <summary>
/// 异步处理消息
/// </summary>
/// <param name="RecoverAsync"></param>
/// <param name="SendAsync"></param>
/// <param name="message"></param>
/// <returns></returns>
public async Task HandleMsgAsync(Func<string, Task> RecoverAsync, string message)
public async Task HandleMsgAsync(Func<string, Task> SendAsync, string message)
{
JObject json = JObject.Parse(message);
await Task.Run(() =>
{
foreach (var module in MyHandleModuleDict.Values)
{
module.HandleSocketMsg(RecoverAsync, json);
module.HandleSocketMsg(SendAsync, json);
}
});