mirror of
https://gitee.com/langsisi_admin/serein-flow
synced 2026-03-03 00:00:49 +08:00
使用emit代替表达式树构造委托。
内置了websocket server与相应的导航功能,可在实例工程中找到相应的实现。
This commit is contained in:
@@ -21,6 +21,6 @@ namespace Serein.Library.Api
|
||||
/// <param name="time"></param>
|
||||
/// <param name="count"></param>
|
||||
/// <returns></returns>
|
||||
Task CreateTimingTask(Action callback, int time = 100, int count = -1);
|
||||
// Task CreateTimingTask(Action callback, int time = 100, int count = -1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -468,7 +468,7 @@ namespace Serein.Library.Api
|
||||
bool TryGetMethodDetails(string methodName, out MethodDetails md);
|
||||
|
||||
|
||||
bool TryGetDelegate(string methodName, out Delegate del);
|
||||
bool TryGetDelegateDetails(string methodName, out DelegateDetails del);
|
||||
|
||||
//bool TryGetNodeData(string methodName, out NodeData node);
|
||||
|
||||
|
||||
28
Library/Entity/DelegateDetails.cs
Normal file
28
Library/Entity/DelegateDetails.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using Serein.Library.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using static Serein.Library.Utils.EmitHelper;
|
||||
|
||||
namespace Serein.Library.Entity
|
||||
{
|
||||
public class DelegateDetails
|
||||
{
|
||||
public DelegateDetails(EmitMethodType EmitMethodType, Delegate EmitDelegate)
|
||||
{
|
||||
this._emitMethodType = EmitMethodType;
|
||||
this._emitDelegate = EmitDelegate;
|
||||
}
|
||||
public void Upload(EmitMethodType EmitMethodType, Delegate EmitDelegate)
|
||||
{
|
||||
_emitMethodType = EmitMethodType;
|
||||
_emitDelegate = EmitDelegate;
|
||||
}
|
||||
private Delegate _emitDelegate;
|
||||
private EmitMethodType _emitMethodType;
|
||||
public Delegate EmitDelegate { get => _emitDelegate; }
|
||||
public EmitMethodType EmitMethodType { get => _emitMethodType; }
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,7 @@ namespace Serein.Library.Entity
|
||||
ActingInstance = ActingInstance,
|
||||
ActingInstanceType = ActingInstanceType,
|
||||
MethodDynamicType = MethodDynamicType,
|
||||
MethodGuid = Guid.NewGuid().ToString(),
|
||||
// MethodGuid = Guid.NewGuid().ToString(),
|
||||
MethodTips = MethodTips,
|
||||
ReturnType = ReturnType,
|
||||
MethodName = MethodName,
|
||||
@@ -56,7 +56,7 @@ namespace Serein.Library.Entity
|
||||
/// 方法GUID
|
||||
/// </summary>
|
||||
|
||||
public string MethodGuid { get; set; }
|
||||
// public string MethodGuid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 方法名称
|
||||
|
||||
@@ -14,10 +14,10 @@ namespace Serein.Library.Web
|
||||
/// HTTP接口监听类
|
||||
/// </summary>
|
||||
[AutoRegister]
|
||||
public class WebServer
|
||||
public class WebApiServer
|
||||
{
|
||||
private readonly IRouter Router;// 路由器
|
||||
public WebServer(IRouter router)
|
||||
public WebApiServer(IRouter router)
|
||||
{
|
||||
this.Router = router;
|
||||
listener = new HttpListener();
|
||||
@@ -33,7 +33,7 @@ namespace Serein.Library.Web
|
||||
|
||||
|
||||
// 启动服务器
|
||||
public WebServer Start(string prefixe)
|
||||
public WebApiServer Start(string prefixe)
|
||||
{
|
||||
|
||||
if (!prefixe.Substring(prefixe.Length - 1, 1).Equals(@"/"))
|
||||
23
Library/Network/WebSocket/Attribute.cs
Normal file
23
Library/Network/WebSocket/Attribute.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
using System.Net.WebSockets;
|
||||
|
||||
namespace Serein.Library.Network.WebSocketCommunication
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
public sealed class AutoSocketHandleAttribute : Attribute
|
||||
{
|
||||
public string ThemeValue;
|
||||
//public Type DataType;
|
||||
}
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public sealed class AutoSocketModuleAttribute : Attribute
|
||||
{
|
||||
public string JsonDataField;
|
||||
public string JsonThemeField;
|
||||
}
|
||||
|
||||
}
|
||||
141
Library/Network/WebSocket/Handle/MyHandleConfig.cs
Normal file
141
Library/Network/WebSocket/Handle/MyHandleConfig.cs
Normal file
@@ -0,0 +1,141 @@
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Serein.Library.Utils;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.Library.Network.WebSocketCommunication.Handle
|
||||
{
|
||||
public class MyHandleConfig
|
||||
{
|
||||
private readonly Delegate EmitDelegate;
|
||||
private readonly EmitHelper.EmitMethodType EmitMethodType;
|
||||
|
||||
public MyHandleConfig(ISocketControlBase instance, MethodInfo methodInfo)
|
||||
{
|
||||
EmitMethodType = EmitHelper.CreateDynamicMethod(methodInfo,out EmitDelegate);
|
||||
|
||||
Instance = instance;
|
||||
var parameterInfos = methodInfo.GetParameters();
|
||||
ParameterType = parameterInfos.Select(t => t.ParameterType).ToArray();
|
||||
ParameterName = parameterInfos.Select(t => t.Name).ToArray();
|
||||
|
||||
}
|
||||
public ISocketControlBase Instance { get; private set; }
|
||||
private string[] ParameterName;
|
||||
private Type[] ParameterType;
|
||||
|
||||
|
||||
public async void Handle(Func<string, Task> RecoverAsync, JObject jsonObject)
|
||||
{
|
||||
object[] args = new object[ParameterType.Length];
|
||||
for (int i = 0; i < ParameterType.Length; i++)
|
||||
{
|
||||
var type = ParameterType[i];
|
||||
var argName = ParameterName[i];
|
||||
if (type.IsGenericType)
|
||||
{
|
||||
if (type.IsAssignableFrom(typeof(Func<object, Task>)))
|
||||
{
|
||||
args[i] = new Func<object, Task>(async data =>
|
||||
{
|
||||
var jsonText = JsonConvert.SerializeObject(data);
|
||||
await RecoverAsync.Invoke(jsonText);
|
||||
});
|
||||
}
|
||||
else if (type.IsAssignableFrom(typeof(Func<string, Task>)))
|
||||
{
|
||||
args[i] = new Func<string, Task>(async data =>
|
||||
{
|
||||
await RecoverAsync.Invoke(data);
|
||||
});
|
||||
}
|
||||
else if (type.IsAssignableFrom(typeof(Action<object>)))
|
||||
{
|
||||
args[i] = new Action<object>(async data =>
|
||||
{
|
||||
var jsonText = JsonConvert.SerializeObject(data);
|
||||
await RecoverAsync.Invoke(jsonText);
|
||||
});
|
||||
}
|
||||
else if (type.IsAssignableFrom(typeof(Action<string>)))
|
||||
{
|
||||
args[i] = new Action<string>(async data =>
|
||||
{
|
||||
var jsonText = JsonConvert.SerializeObject(data);
|
||||
await RecoverAsync.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();
|
||||
object result;
|
||||
if (EmitMethodType == EmitHelper.EmitMethodType.HasResultTask && EmitDelegate is Func<object, object[], Task<object>> hasResultTask)
|
||||
{
|
||||
result = await hasResultTask(Instance, args);
|
||||
}
|
||||
else if (EmitMethodType == EmitHelper.EmitMethodType.Task && EmitDelegate is Func<object, object[], Task> task)
|
||||
{
|
||||
await task.Invoke(Instance, args);
|
||||
result = null;
|
||||
}
|
||||
else if (EmitMethodType == EmitHelper.EmitMethodType.Func && EmitDelegate is Func<object, object[], object> func)
|
||||
{
|
||||
result = func.Invoke(Instance, args);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException("构造委托无法正确调用");
|
||||
}
|
||||
sw.Stop();
|
||||
Console.WriteLine($"Emit Invoke:{sw.ElapsedTicks * 1000000F / Stopwatch.Frequency:n3}μs");
|
||||
|
||||
if(result != null && result.GetType().IsClass)
|
||||
{
|
||||
var reusltJsonText = JsonConvert.SerializeObject(result);
|
||||
_ = RecoverAsync.Invoke($"{reusltJsonText}");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
public void Clear()
|
||||
{
|
||||
Instance = null;
|
||||
ParameterName = null;
|
||||
ParameterType = null;
|
||||
//expressionDelegate = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
69
Library/Network/WebSocket/Handle/MyHandleModule.cs
Normal file
69
Library/Network/WebSocket/Handle/MyHandleModule.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.Library.Network.WebSocketCommunication.Handle
|
||||
{
|
||||
public class MyHandleModule
|
||||
{
|
||||
public MyHandleModule(string ThemeJsonKey, string DataJsonKey)
|
||||
{
|
||||
this.ThemeJsonKey = ThemeJsonKey;
|
||||
this.DataJsonKey = DataJsonKey;
|
||||
}
|
||||
public string ThemeJsonKey { get; }
|
||||
public string DataJsonKey { get; }
|
||||
|
||||
public ConcurrentDictionary<string, MyHandleConfig> MyHandleConfigs = new ConcurrentDictionary<string, MyHandleConfig>();
|
||||
public void AddHandleConfigs(string themeValue, ISocketControlBase instance, MethodInfo methodInfo)
|
||||
{
|
||||
if (!MyHandleConfigs.ContainsKey(themeValue))
|
||||
{
|
||||
var myHandleConfig = new MyHandleConfig(instance, methodInfo);
|
||||
MyHandleConfigs[themeValue] = myHandleConfig;
|
||||
}
|
||||
}
|
||||
public void ResetConfig(ISocketControlBase socketControlBase)
|
||||
{
|
||||
foreach (var kv in MyHandleConfigs.ToArray())
|
||||
{
|
||||
var config = kv.Value;
|
||||
if (config.Instance.HandleGuid.Equals(socketControlBase.HandleGuid))
|
||||
{
|
||||
MyHandleConfigs.TryRemove(kv.Key, out _);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ResetConfig()
|
||||
{
|
||||
var temp = MyHandleConfigs.Values;
|
||||
MyHandleConfigs.Clear();
|
||||
foreach (var config in temp)
|
||||
{
|
||||
config.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void HandleSocketMsg(Func<string, Task> RecoverAsync, JObject jsonObject)
|
||||
{
|
||||
// 获取到消息
|
||||
string themeKeyName = jsonObject.GetValue(ThemeJsonKey)?.ToString();
|
||||
if (!MyHandleConfigs.TryGetValue(themeKeyName, out var handldConfig))
|
||||
{
|
||||
// 没有主题
|
||||
return;
|
||||
}
|
||||
if (jsonObject[DataJsonKey] is JObject dataJsonObject)
|
||||
{
|
||||
handldConfig.Handle(RecoverAsync, dataJsonObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
118
Library/Network/WebSocket/Handle/SocketMsgHandleHelper.cs
Normal file
118
Library/Network/WebSocket/Handle/SocketMsgHandleHelper.cs
Normal file
@@ -0,0 +1,118 @@
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.WebSockets;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Newtonsoft.Json;
|
||||
using Serein.Library.Utils;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Linq.Expressions;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace Serein.Library.Network.WebSocketCommunication.Handle
|
||||
{
|
||||
|
||||
public class SocketMsgHandleHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// (Theme Name ,Data Name) - HandleModule
|
||||
/// </summary>
|
||||
public ConcurrentDictionary<(string, string), MyHandleModule> MyHandleModuleDict
|
||||
= new ConcurrentDictionary<(string, string), MyHandleModule>();
|
||||
|
||||
|
||||
|
||||
private MyHandleModule AddMyHandleModule(string themeKeyName, string dataKeyName)
|
||||
{
|
||||
var key = (themeKeyName, dataKeyName);
|
||||
if (!MyHandleModuleDict.TryGetValue(key, out var myHandleModule))
|
||||
{
|
||||
myHandleModule = new MyHandleModule(themeKeyName, dataKeyName);
|
||||
MyHandleModuleDict[key] = myHandleModule;
|
||||
}
|
||||
return myHandleModule;
|
||||
}
|
||||
|
||||
public void RemoteModule(ISocketControlBase socketControlBase)
|
||||
{
|
||||
var type = socketControlBase.GetType();
|
||||
var moduleAttribute = type.GetCustomAttribute<AutoSocketModuleAttribute>();
|
||||
if (moduleAttribute is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var themeKeyName = moduleAttribute.JsonThemeField;
|
||||
var dataKeyName = moduleAttribute.JsonDataField;
|
||||
var key = (themeKeyName, dataKeyName);
|
||||
if (MyHandleModuleDict.TryRemove(key, out var myHandleModules))
|
||||
{
|
||||
myHandleModules.ResetConfig(socketControlBase);
|
||||
}
|
||||
|
||||
}
|
||||
public void AddModule(ISocketControlBase socketControlBase)
|
||||
{
|
||||
var type = socketControlBase.GetType();
|
||||
var moduleAttribute = type.GetCustomAttribute<AutoSocketModuleAttribute>();
|
||||
if (moduleAttribute is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 添加处理模块
|
||||
var themeKey = moduleAttribute.JsonThemeField;
|
||||
var dataKey = moduleAttribute.JsonDataField;
|
||||
|
||||
var handlemodule = AddMyHandleModule(themeKey, dataKey);
|
||||
var methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
|
||||
.Select(method =>
|
||||
{
|
||||
var methodsAttribute = method.GetCustomAttribute<AutoSocketHandleAttribute>();
|
||||
if (methodsAttribute is null)
|
||||
{
|
||||
return (string.Empty, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
var value = methodsAttribute.ThemeValue;
|
||||
return (value, method);
|
||||
}
|
||||
})
|
||||
.Where(x => !string.IsNullOrEmpty(x.value)).ToList();
|
||||
if (methods.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ((var value, var method) in methods)
|
||||
{
|
||||
handlemodule.AddHandleConfigs(value, socketControlBase, method);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public async Task HandleMsgAsync(Func<string, Task> RecoverAsync, string message)
|
||||
{
|
||||
JObject json = JObject.Parse(message);
|
||||
await Task.Run(() =>
|
||||
{
|
||||
foreach (var module in MyHandleModuleDict.Values)
|
||||
{
|
||||
module.HandleSocketMsg(RecoverAsync, json);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
41
Library/Network/WebSocket/SocketControlBase.cs
Normal file
41
Library/Network/WebSocket/SocketControlBase.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using Serein.Library.Attributes;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.WebSockets;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.Library.Network.WebSocketCommunication
|
||||
{
|
||||
public interface ISocketControlBase
|
||||
{
|
||||
Guid HandleGuid { get; }
|
||||
}
|
||||
|
||||
|
||||
//[AutoRegister(RegisterSequence.FlowLoading)]
|
||||
//[AutoSocketModule(JsonThemeField = "theme", JsonDataField = "data")]
|
||||
//public class UserService : ISocketControlBase
|
||||
//{
|
||||
// public Guid HandleGuid { get; } = new Guid();
|
||||
|
||||
// // Action<string> 类型是特殊的,会用一个委托代替,这个委托可以将文本信息发送到客户端
|
||||
// // Action<object> 类型是特殊的,会用一个委托代替,这个委托可以将对象转成json发送到客户端
|
||||
|
||||
// [AutoSocketHandle]
|
||||
// public void AddUser(User user,Action<string> Recover)
|
||||
// {
|
||||
// Console.WriteLine(user.ToString());
|
||||
// Recover("ok");
|
||||
// }
|
||||
|
||||
// [AutoSocketHandle(ThemeValue = "Remote")]
|
||||
// public void DeleteUser(User user, Action<string> Recover)
|
||||
// {
|
||||
// Console.WriteLine(user.ToString());
|
||||
// }
|
||||
|
||||
//}
|
||||
|
||||
}
|
||||
136
Library/Network/WebSocket/WebSocketClient.cs
Normal file
136
Library/Network/WebSocket/WebSocketClient.cs
Normal file
@@ -0,0 +1,136 @@
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Serein.Library.Attributes;
|
||||
using Serein.Library.Web;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Net.WebSockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.Library.Network.WebSocketCommunication
|
||||
{
|
||||
|
||||
|
||||
[AutoRegister]
|
||||
public class WebSocketClient
|
||||
{
|
||||
public WebSocketClient()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
private ClientWebSocket _client = new ClientWebSocket();
|
||||
|
||||
|
||||
public async Task ConnectAsync(string uri)
|
||||
{
|
||||
await _client.ConnectAsync(new Uri(uri), CancellationToken.None);
|
||||
await ReceiveAsync();
|
||||
}
|
||||
|
||||
|
||||
public async Task SendAsync(WebSocket webSocket,string message)
|
||||
{
|
||||
var buffer = Encoding.UTF8.GetBytes(message);
|
||||
await webSocket.SendAsync(new ArraySegment<byte>(buffer), WebSocketMessageType.Text, true, CancellationToken.None);
|
||||
}
|
||||
|
||||
private async Task ReceiveAsync()
|
||||
{
|
||||
var buffer = new byte[1024];
|
||||
while (_client.State == WebSocketState.Open)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await _client.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
|
||||
if (result.MessageType == WebSocketMessageType.Close)
|
||||
{
|
||||
await _client.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None);
|
||||
}
|
||||
else
|
||||
{
|
||||
var message = Encoding.UTF8.GetString(buffer, 0, result.Count);
|
||||
|
||||
|
||||
Debug.WriteLine($"Received: {message}");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
await Console.Out.WriteLineAsync(ex.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* #region 消息处理
|
||||
private readonly string ThemeField;
|
||||
private readonly ConcurrentDictionary<string, HandldConfig> ThemeConfigs = new ConcurrentDictionary<string, HandldConfig>();
|
||||
|
||||
public async Task HandleSocketMsg(string jsonStr)
|
||||
{
|
||||
JObject json;
|
||||
try
|
||||
{
|
||||
json = JObject.Parse(jsonStr);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await SendAsync(_client, ex.Message);
|
||||
return;
|
||||
}
|
||||
// 获取到消息
|
||||
string themeName = json[ThemeField]?.ToString();
|
||||
if (!ThemeConfigs.TryGetValue(themeName, out var handldConfig))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
object dataValue;
|
||||
if (string.IsNullOrEmpty(handldConfig.DataField))
|
||||
{
|
||||
dataValue = json.ToObject(handldConfig.DataType);
|
||||
}
|
||||
else
|
||||
{
|
||||
dataValue = json[handldConfig.DataField].ToObject(handldConfig.DataType);
|
||||
}
|
||||
await handldConfig.Invoke(dataValue, SendAsync);
|
||||
}
|
||||
|
||||
public void AddConfig(string themeName, Type dataType, MsgHandler msgHandler)
|
||||
{
|
||||
if (!ThemeConfigs.TryGetValue(themeName, out var handldConfig))
|
||||
{
|
||||
handldConfig = new HandldConfig
|
||||
{
|
||||
DataField = themeName,
|
||||
DataType = dataType
|
||||
};
|
||||
ThemeConfigs.TryAdd(themeName, handldConfig);
|
||||
}
|
||||
handldConfig.HandldAsync += msgHandler;
|
||||
}
|
||||
public void RemoteConfig(string themeName, MsgHandler msgHandler)
|
||||
{
|
||||
if (ThemeConfigs.TryGetValue(themeName, out var handldConfig))
|
||||
{
|
||||
handldConfig.HandldAsync -= msgHandler;
|
||||
if (!handldConfig.HasSubscribers)
|
||||
{
|
||||
ThemeConfigs.TryRemove(themeName, out _);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion*/
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Serein.Library.Network.WebSocketCommunication
|
||||
{
|
||||
public class WebSocketRouter
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,57 +1,103 @@
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Serein.Library.Attributes;
|
||||
using Serein.Library.Network.WebSocketCommunication.Handle;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.WebSockets;
|
||||
using System.Reflection;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.Library.Network.WebSocketCommunication
|
||||
{
|
||||
[AutoRegister]
|
||||
public class WebSocketServer
|
||||
{
|
||||
public Func<string,Action> OnReceiveMsg;
|
||||
public WebSocketServer()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
public SocketMsgHandleHelper MsgHandleHelper { get; } = new SocketMsgHandleHelper();
|
||||
|
||||
HttpListener listener;
|
||||
public async Task StartAsync(string url)
|
||||
{
|
||||
HttpListener listener = new HttpListener();
|
||||
listener = new HttpListener();
|
||||
listener.Prefixes.Add(url);
|
||||
listener.Start();
|
||||
|
||||
while (true)
|
||||
{
|
||||
var context = await listener.GetContextAsync();
|
||||
if (context.Request.IsWebSocketRequest)
|
||||
try
|
||||
{
|
||||
var webSocketContext = await context.AcceptWebSocketAsync(null); //新连接
|
||||
_ = HandleWebSocketAsync(webSocketContext.WebSocket); // 处理消息
|
||||
var context = await listener.GetContextAsync();
|
||||
string clientPoint = context.Request.RemoteEndPoint?.ToString();
|
||||
|
||||
await Console.Out.WriteLineAsync($"新的连接加入:{clientPoint}");
|
||||
if (context.Request.IsWebSocketRequest)
|
||||
{
|
||||
var webSocketContext = await context.AcceptWebSocketAsync(null); //新连接
|
||||
|
||||
_ = HandleWebSocketAsync(webSocketContext.WebSocket); // 处理消息
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await Console.Out.WriteLineAsync(ex.Message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
listener?.Stop();
|
||||
}
|
||||
|
||||
private async Task HandleWebSocketAsync(WebSocket webSocket)
|
||||
{
|
||||
Func<string,Task> SendAsync = async (text) =>
|
||||
{
|
||||
await WebSocketServer.SendAsync(webSocket, text);
|
||||
};
|
||||
var buffer = new byte[1024];
|
||||
while (webSocket.State == WebSocketState.Open)
|
||||
{
|
||||
var result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
|
||||
if (result.MessageType == WebSocketMessageType.Close)
|
||||
{
|
||||
SendAsync = null;
|
||||
await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None);
|
||||
}
|
||||
else
|
||||
{
|
||||
var message = Encoding.UTF8.GetString(buffer, 0, result.Count);
|
||||
Console.WriteLine($"Received: {message}");
|
||||
var action = OnReceiveMsg.Invoke(message);
|
||||
action?.Invoke();
|
||||
|
||||
// 回显消息(可选)
|
||||
//ar echoMessage = Encoding.UTF8.GetBytes(message);
|
||||
|
||||
_ = MsgHandleHelper.HandleMsgAsync(SendAsync, message);
|
||||
|
||||
//foreach (var item in HandldHelpers)
|
||||
//{
|
||||
// await item.HandleSocketMsg(webSocket, message);
|
||||
//}
|
||||
//Console.WriteLine($"Received: {message}");
|
||||
//var echoMessage = Encoding.UTF8.GetBytes(message);
|
||||
//await webSocket.SendAsync(new ArraySegment<byte>(echoMessage, 0, echoMessage.Length), result.MessageType, result.EndOfMessage, CancellationToken.None);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task SendAsync(WebSocket webSocket, string message)
|
||||
{
|
||||
var buffer = Encoding.UTF8.GetBytes(message);
|
||||
await webSocket.SendAsync(new ArraySegment<byte>(buffer), WebSocketMessageType.Text, true, CancellationToken.None);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,12 +11,31 @@ namespace Serein.Library.Attributes
|
||||
{
|
||||
}
|
||||
|
||||
public enum RegisterSequence
|
||||
{ /// <summary>
|
||||
/// 不自动初始化
|
||||
/// </summary>
|
||||
Node,
|
||||
/// <summary>
|
||||
/// 初始化后
|
||||
/// </summary>
|
||||
FlowInit,
|
||||
/// <summary>
|
||||
/// 加载后
|
||||
/// </summary>
|
||||
FlowLoading,
|
||||
}
|
||||
/// <summary>
|
||||
/// 表示该类自动注册(单例模式)
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public sealed class AutoRegisterAttribute : Attribute
|
||||
{
|
||||
public AutoRegisterAttribute(RegisterSequence Class = RegisterSequence.FlowInit)
|
||||
{
|
||||
this.Class = Class;
|
||||
}
|
||||
public RegisterSequence Class ;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>netstandard2.0;net462</TargetFrameworks>
|
||||
<TargetFrameworks>net8-windows;net462</TargetFrameworks>
|
||||
<BaseOutputPath>D:\Project\C#\DynamicControl\SereinFlow\.Output</BaseOutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -21,4 +21,8 @@
|
||||
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Network\Socket\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
151
Library/Utils/EmitHelper.cs
Normal file
151
Library/Utils/EmitHelper.cs
Normal file
@@ -0,0 +1,151 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.Library.Utils
|
||||
{
|
||||
public class EmitHelper
|
||||
{
|
||||
public enum EmitMethodType
|
||||
{
|
||||
Func,
|
||||
Task,
|
||||
HasResultTask,
|
||||
}
|
||||
public static bool IsGenericTask(Type returnType, out Type taskResult)
|
||||
{
|
||||
// 判断是否为 Task 类型或泛型 Task<T>
|
||||
if (returnType == typeof(Task))
|
||||
{
|
||||
taskResult = null;
|
||||
return true;
|
||||
}
|
||||
else if (returnType.IsGenericType && returnType.GetGenericTypeDefinition() == typeof(Task<>))
|
||||
{
|
||||
// 获取泛型参数类型
|
||||
Type genericArgument = returnType.GetGenericArguments()[0];
|
||||
taskResult = genericArgument;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
taskResult = null;
|
||||
return false;
|
||||
|
||||
}
|
||||
}
|
||||
//public static Delegate CreateDynamicMethod<T>(MethodInfo methodInfo)
|
||||
//{
|
||||
// return CreateDynamicMethod(methodInfo);
|
||||
//}
|
||||
|
||||
public static EmitMethodType CreateDynamicMethod( MethodInfo methodInfo,out Delegate @delegate)
|
||||
{
|
||||
bool IsTask = IsGenericTask(methodInfo.ReturnType, out var taskGenericsType);
|
||||
bool IsTaskGenerics = taskGenericsType != null;
|
||||
DynamicMethod dynamicMethod;
|
||||
if (IsTask)
|
||||
{
|
||||
if (IsTaskGenerics)
|
||||
{
|
||||
|
||||
dynamicMethod = new DynamicMethod(
|
||||
name: methodInfo.Name + "_DynamicMethod",
|
||||
returnType: typeof(Task<object>),
|
||||
parameterTypes: new[] { typeof(object), typeof(object[]) },
|
||||
restrictedSkipVisibility: true // 跳过私有方法访问限制
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
dynamicMethod = new DynamicMethod(
|
||||
name: methodInfo.Name + "_DynamicMethod",
|
||||
returnType: typeof(Task),
|
||||
parameterTypes: new[] { typeof(object), typeof(object[]) },
|
||||
restrictedSkipVisibility: true // 跳过私有方法访问限制
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dynamicMethod = new DynamicMethod(
|
||||
name: methodInfo.Name + "_DynamicMethod",
|
||||
returnType: typeof(object),
|
||||
parameterTypes: new[] { typeof(object), typeof(object[]) },
|
||||
restrictedSkipVisibility: true // 跳过私有方法访问限制
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
var il = dynamicMethod.GetILGenerator();
|
||||
|
||||
// 加载实例 (this)
|
||||
il.Emit(OpCodes.Ldarg_0);
|
||||
il.Emit(OpCodes.Castclass, methodInfo.DeclaringType); // 将 ISocketControlBase 转换为目标类类型
|
||||
|
||||
// 加载方法参数
|
||||
var methodParams = methodInfo.GetParameters();
|
||||
for (int i = 0; i < methodParams.Length; i++)
|
||||
{
|
||||
il.Emit(OpCodes.Ldarg_1); // 加载参数数组
|
||||
il.Emit(OpCodes.Ldc_I4, i); // 加载当前参数索引
|
||||
il.Emit(OpCodes.Ldelem_Ref); // 取出数组元素
|
||||
|
||||
var paramType = methodParams[i].ParameterType;
|
||||
if (paramType.IsValueType) // 如果参数是值类型,拆箱
|
||||
{
|
||||
il.Emit(OpCodes.Unbox_Any, paramType);
|
||||
}
|
||||
else // 如果是引用类型,直接转换
|
||||
{
|
||||
il.Emit(OpCodes.Castclass, paramType);
|
||||
}
|
||||
}
|
||||
|
||||
// 调用方法
|
||||
il.Emit(OpCodes.Callvirt, methodInfo);
|
||||
|
||||
//// 处理返回值,如果没有返回值,则返回null
|
||||
if (methodInfo.ReturnType == typeof(void))
|
||||
{
|
||||
il.Emit(OpCodes.Ldnull);
|
||||
}
|
||||
else if (methodInfo.ReturnType.IsValueType)
|
||||
{
|
||||
il.Emit(OpCodes.Box, methodInfo.ReturnType); // 如果是值类型,将其装箱
|
||||
}
|
||||
// 处理返回值,如果没有返回值,则返回null
|
||||
il.Emit(OpCodes.Ret); // 返回
|
||||
EmitMethodType emitMethodType;
|
||||
if (IsTask)
|
||||
{
|
||||
if (IsTaskGenerics)
|
||||
{
|
||||
emitMethodType = EmitMethodType.HasResultTask;
|
||||
@delegate = dynamicMethod.CreateDelegate(typeof(Func<object, object[], Task<object>>));
|
||||
}
|
||||
else
|
||||
{
|
||||
emitMethodType = EmitMethodType.Task;
|
||||
@delegate = dynamicMethod.CreateDelegate(typeof(Func<object, object[], Task>));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
emitMethodType = EmitMethodType.Func;
|
||||
@delegate = dynamicMethod.CreateDelegate(typeof(Func<object, object[], object>));
|
||||
|
||||
}
|
||||
return emitMethodType;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
446
Library/Utils/ExpressionHelper.cs
Normal file
446
Library/Utils/ExpressionHelper.cs
Normal file
@@ -0,0 +1,446 @@
|
||||
using Serein.Library.Api;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Serein.Library.Utils
|
||||
{
|
||||
/// <summary>
|
||||
/// 基于类型创建表达式树反射委托
|
||||
/// </summary>
|
||||
public static class ExpressionHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 缓存表达式树反射方法
|
||||
/// </summary>
|
||||
private static ConcurrentDictionary<string, Delegate> Cache { get; } = new ConcurrentDictionary<string, Delegate>();
|
||||
|
||||
|
||||
#region 基于类型的表达式反射构建委托
|
||||
|
||||
#region 属性、字段的委托创建(表达式反射)
|
||||
|
||||
/// <summary>
|
||||
/// 动态获取属性值
|
||||
/// </summary>
|
||||
public static Delegate PropertyGetter(Type type, string propertyName)
|
||||
{
|
||||
string cacheKey = $"{type.FullName}.{propertyName}.Getter";
|
||||
return Cache.GetOrAdd(cacheKey, _ => CreateGetterDelegate(type, propertyName));
|
||||
}
|
||||
/// <summary>
|
||||
/// 动态获取属性值
|
||||
/// </summary>
|
||||
private static Delegate CreateGetterDelegate(Type type, string propertyName)
|
||||
{
|
||||
var parameter = Expression.Parameter(typeof(object), "instance");
|
||||
var property = Expression.Property(Expression.Convert(parameter, type), propertyName);
|
||||
var lambda = Expression.Lambda(Expression.Convert(property, typeof(object)), parameter);
|
||||
return lambda.Compile();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 动态设置属性值
|
||||
/// </summary>
|
||||
public static Delegate PropertySetter(Type type, string propertyName)
|
||||
{
|
||||
string cacheKey = $"{type.FullName}.{propertyName}.Setter";
|
||||
return Cache.GetOrAdd(cacheKey, _ => CreateSetterDelegate(type, propertyName));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 动态设置属性值
|
||||
/// </summary>
|
||||
private static Delegate CreateSetterDelegate(Type type, string propertyName)
|
||||
{
|
||||
var parameter = Expression.Parameter(typeof(object), "instance");
|
||||
var value = Expression.Parameter(typeof(object), "value");
|
||||
var property = Expression.Property(Expression.Convert(parameter, type), propertyName);
|
||||
var assign = Expression.Assign(property, Expression.Convert(value, property.Type));
|
||||
var lambda = Expression.Lambda(assign, parameter, value);
|
||||
return lambda.Compile();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 动态获取字段值
|
||||
/// </summary>
|
||||
public static Delegate FieldGetter(Type type, string fieldName)
|
||||
{
|
||||
string cacheKey = $"{type.FullName}.{fieldName}.FieldGetter";
|
||||
return Cache.GetOrAdd(cacheKey, _ => CreateFieldGetterDelegate(type, fieldName));
|
||||
}
|
||||
/// <summary>
|
||||
/// 动态获取字段值
|
||||
/// </summary>
|
||||
private static Delegate CreateFieldGetterDelegate(Type type, string fieldName)
|
||||
{
|
||||
var parameter = Expression.Parameter(typeof(object), "instance");
|
||||
var field = Expression.Field(Expression.Convert(parameter, type), fieldName);
|
||||
var lambda = Expression.Lambda(Expression.Convert(field, typeof(object)), parameter);
|
||||
return lambda.Compile();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 动态设置字段值
|
||||
/// </summary>
|
||||
public static Delegate FieldSetter(Type type, string fieldName)
|
||||
{
|
||||
string cacheKey = $"{type.FullName}.{fieldName}.FieldSetter";
|
||||
return Cache.GetOrAdd(cacheKey, _ => CreateFieldSetterDelegate(type, fieldName));
|
||||
}
|
||||
/// <summary>
|
||||
/// 动态设置字段值
|
||||
/// </summary>
|
||||
private static Delegate CreateFieldSetterDelegate(Type type, string fieldName)
|
||||
{
|
||||
var parameter = Expression.Parameter(typeof(object), "instance");
|
||||
var value = Expression.Parameter(typeof(object), "value");
|
||||
var field = Expression.Field(Expression.Convert(parameter, type), fieldName);
|
||||
var assign = Expression.Assign(field, Expression.Convert(value, field.Type));
|
||||
var lambda = Expression.Lambda(assign, parameter, value);
|
||||
return lambda.Compile();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 表达式树构建无参数,无返回值方法
|
||||
/// </summary>
|
||||
public static Delegate MethodCaller(Type type, MethodInfo methodInfo)
|
||||
{
|
||||
string cacheKey = $"{type.FullName}.{methodInfo.Name}.MethodCaller";
|
||||
return Cache.GetOrAdd(cacheKey, _ => CreateMethodCallerDelegate(type, methodInfo));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 表达式树构建无参数,无返回值方法
|
||||
/// </summary>
|
||||
private static Delegate CreateMethodCallerDelegate(Type type, MethodInfo methodInfo)
|
||||
{
|
||||
var parameter = Expression.Parameter(typeof(object), "instance");
|
||||
var methodCall = Expression.Call(Expression.Convert(parameter, type), methodInfo);
|
||||
var lambda = Expression.Lambda(methodCall, parameter);
|
||||
// Action<object>
|
||||
return lambda.Compile();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 表达式树构建无参数,有返回值方法
|
||||
/// </summary>
|
||||
public static Delegate MethodCallerHaveResult(Type type, MethodInfo methodInfo)
|
||||
{
|
||||
string cacheKey = $"{type.FullName}.{methodInfo.Name}.MethodCallerHaveResult";
|
||||
return Cache.GetOrAdd(cacheKey, _ => CreateMethodCallerDelegateHaveResult(type, methodInfo));
|
||||
}
|
||||
/// <summary>
|
||||
/// 表达式树构建无参数,有返回值方法
|
||||
/// </summary>
|
||||
private static Delegate CreateMethodCallerDelegateHaveResult(Type type, MethodInfo methodInfo)
|
||||
{
|
||||
var parameter = Expression.Parameter(typeof(object), "instance");
|
||||
var methodCall = Expression.Call(Expression.Convert(parameter, type), methodInfo);
|
||||
|
||||
if (IsGenericTask(methodInfo.ReturnType, out var taskResult))
|
||||
{
|
||||
if (taskResult is null)
|
||||
{
|
||||
var lambda = Expression.Lambda<Func<object, Task>>(Expression.Convert(methodCall, typeof(Task)), parameter);
|
||||
return lambda.Compile();
|
||||
}
|
||||
else
|
||||
{
|
||||
var lambda = Expression.Lambda<Func<object, Task<object>>>(Expression.Convert(methodCall, typeof(Task<object>)), parameter);
|
||||
return lambda.Compile();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var lambda = Expression.Lambda<Func<object, object>>(Expression.Convert(methodCall, typeof(object)), parameter);
|
||||
return lambda.Compile();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 表达式树构建多个参数,无返回值的方法
|
||||
/// </summary>
|
||||
public static Delegate MethodCaller(Type type, MethodInfo methodInfo, params Type[] parameterTypes)
|
||||
{
|
||||
string cacheKey = $"{type.FullName}.{methodInfo.Name}.MethodCaller";
|
||||
return Cache.GetOrAdd(cacheKey, _ => CreateMethodCallerDelegate(type, methodInfo, parameterTypes));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 表达式树构建多个参数,无返回值的方法
|
||||
/// </summary>
|
||||
private static Delegate CreateMethodCallerDelegate(Type type, MethodInfo methodInfo, Type[] parameterTypes)
|
||||
{
|
||||
/* var parameter = Expression.Parameter(typeof(object), "instance");
|
||||
|
||||
var arguments = parameterTypes.Select((t, i) => Expression.Parameter(typeof(object), $"arg{i}")).ToArray();
|
||||
|
||||
var convertedArguments = arguments.Select((arg, i) => Expression.Convert(arg, parameterTypes[i])).ToArray();
|
||||
var methodCall = Expression.Call(Expression.Convert(parameter, type),
|
||||
methodInfo,
|
||||
convertedArguments);
|
||||
var lambda = Expression.Lambda(methodCall, new[] { parameter }.Concat(arguments));
|
||||
var tmpAction = lambda.Compile();
|
||||
|
||||
// Action<object, object[]>
|
||||
return lambda.Compile();*/
|
||||
|
||||
var instanceParam = Expression.Parameter(typeof(object), "instance");
|
||||
var argsParam = Expression.Parameter(typeof(object[]), "args");
|
||||
|
||||
// 创建参数表达式
|
||||
var convertedArgs = parameterTypes.Select((paramType, index) =>
|
||||
Expression.Convert(Expression.ArrayIndex(argsParam, Expression.Constant(index)), paramType)
|
||||
).ToArray();
|
||||
|
||||
|
||||
// 创建方法调用表达式
|
||||
var methodCall = Expression.Call(
|
||||
Expression.Convert(instanceParam, type),
|
||||
methodInfo,
|
||||
convertedArgs
|
||||
);
|
||||
|
||||
// 创建 lambda 表达式
|
||||
var lambda = Expression.Lambda(
|
||||
methodCall,
|
||||
instanceParam,
|
||||
argsParam
|
||||
);
|
||||
|
||||
// Func<object, object[], object>
|
||||
return lambda.Compile();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 表达式树构建多个参数,有返回值的方法
|
||||
/// </summary>
|
||||
public static Delegate MethodCallerHaveResult(Type type, MethodInfo methodInfo, Type[] parameterTypes)
|
||||
{
|
||||
string cacheKey = $"{type.FullName}.{methodInfo.Name}.MethodCallerHaveResult";
|
||||
return Cache.GetOrAdd(cacheKey, _ => CreateMethodCallerDelegateHaveResult(type, methodInfo, parameterTypes));
|
||||
}
|
||||
/// <summary>
|
||||
/// 表达式树构建多个参数,有返回值的方法
|
||||
/// </summary>
|
||||
private static Delegate CreateMethodCallerDelegateHaveResult(Type type, MethodInfo methodInfo, Type[] parameterTypes)
|
||||
{
|
||||
/*var instanceParam = Expression.Parameter(typeof(object), "instance");
|
||||
var argsParam = Expression.Parameter(typeof(object[]), "args");
|
||||
|
||||
// 创建参数表达式
|
||||
var convertedArgs = parameterTypes.Select((paramType, index) =>
|
||||
Expression.Convert(Expression.ArrayIndex(argsParam, Expression.Constant(index)), paramType)
|
||||
).ToArray();
|
||||
|
||||
|
||||
// 创建方法调用表达式
|
||||
var methodCall = Expression.Call(
|
||||
Expression.Convert(instanceParam, type),
|
||||
methodInfo,
|
||||
convertedArgs
|
||||
);
|
||||
|
||||
// 创建 lambda 表达式
|
||||
var lambda = Expression.Lambda(
|
||||
Expression.Convert(methodCall, typeof(object)),
|
||||
instanceParam,
|
||||
argsParam
|
||||
);
|
||||
|
||||
// Func<object, object[], object>
|
||||
return lambda.Compile();*/
|
||||
|
||||
var instanceParam = Expression.Parameter(typeof(object), "instance");
|
||||
var argsParam = Expression.Parameter(typeof(object[]), "args");
|
||||
|
||||
// 创建参数表达式
|
||||
var convertedArgs = parameterTypes.Select((paramType, index) =>
|
||||
Expression.Convert(Expression.ArrayIndex(argsParam, Expression.Constant(index)), paramType)
|
||||
).ToArray();
|
||||
|
||||
|
||||
// 创建方法调用表达式
|
||||
var methodCall = Expression.Call(
|
||||
Expression.Convert(instanceParam, type),
|
||||
methodInfo,
|
||||
convertedArgs
|
||||
);
|
||||
|
||||
if (IsGenericTask(methodInfo.ReturnType, out var taskResult))
|
||||
{
|
||||
if (taskResult is null)
|
||||
{
|
||||
var lambda = Expression.Lambda<Func<object, object[], Task>>
|
||||
(Expression.Convert(methodCall, typeof(Task)), instanceParam, argsParam);
|
||||
return lambda.Compile();
|
||||
}
|
||||
else
|
||||
{
|
||||
var lambda = Expression.Lambda<Func<object, object[], Task<object>>>
|
||||
(Expression.Convert(methodCall, typeof(Task<object>)), instanceParam, argsParam);
|
||||
return lambda.Compile();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var lambda = Expression.Lambda<Func<object, object[], object>>
|
||||
(Expression.Convert(methodCall, typeof(object)), instanceParam, argsParam);
|
||||
return lambda.Compile();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 表达式树构建无参数,有返回值(Task<object>)的方法(触发器)
|
||||
/// </summary>
|
||||
public static Delegate MethodCallerAsync(Type type, MethodInfo methodInfo)
|
||||
{
|
||||
string cacheKey = $"{type.FullName}.{methodInfo.Name}.MethodCallerAsync";
|
||||
return Cache.GetOrAdd(cacheKey, _ => CreateMethodCallerDelegateAsync(type, methodInfo));
|
||||
}
|
||||
/// <summary>
|
||||
/// 表达式树构建无参数,有返回值(Task<object>)的方法(触发器)
|
||||
/// </summary>
|
||||
private static Delegate CreateMethodCallerDelegateAsync(Type type, MethodInfo methodInfo)
|
||||
{
|
||||
var parameter = Expression.Parameter(typeof(object), "instance");
|
||||
var methodCall = Expression.Call(Expression.Convert(parameter, type), methodInfo);
|
||||
var lambda = Expression.Lambda<Func<object, Task<object>>>(
|
||||
Expression.Convert(methodCall, typeof(Task<object>)), parameter);
|
||||
// Func<object, Task<object>>
|
||||
return lambda.Compile();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 表达式树构建多个参数,有返回值(Task-object)的方法(触发器)
|
||||
/// </summary>
|
||||
public static Delegate MethodCallerAsync(Type type, MethodInfo method, params Type[] parameterTypes)
|
||||
{
|
||||
|
||||
string cacheKey = $"{type.FullName}.{method.Name}.MethodCallerAsync";
|
||||
return Cache.GetOrAdd(cacheKey, _ => CreateMethodCallerDelegateAsync(type, method, parameterTypes));
|
||||
}
|
||||
/// <summary>
|
||||
/// 表达式树构建多个参数,有返回值(Task<object>)的方法(触发器)
|
||||
/// </summary>
|
||||
private static Delegate CreateMethodCallerDelegateAsync(Type type, MethodInfo methodInfo, Type[] parameterTypes)
|
||||
{
|
||||
var instanceParam = Expression.Parameter(typeof(object), "instance");
|
||||
var argsParam = Expression.Parameter(typeof(object[]), "args");
|
||||
|
||||
// 创建参数表达式
|
||||
var convertedArgs = parameterTypes.Select((paramType, index) =>
|
||||
Expression.Convert(Expression.ArrayIndex(argsParam, Expression.Constant(index)), paramType)
|
||||
).ToArray();
|
||||
|
||||
|
||||
// 创建方法调用表达式
|
||||
var methodCall = Expression.Call(
|
||||
Expression.Convert(instanceParam, type),
|
||||
methodInfo,
|
||||
convertedArgs
|
||||
);
|
||||
|
||||
// 创建 lambda 表达式
|
||||
var lambda = Expression.Lambda<Func<object, object[], Task<IFlipflopContext>>>(
|
||||
Expression.Convert(methodCall, typeof(Task<IFlipflopContext>)),
|
||||
instanceParam,
|
||||
argsParam
|
||||
);
|
||||
//获取返回类型
|
||||
//var returnType = methodInfo.ReturnType;
|
||||
//var lambda = Expression.Lambda(
|
||||
// typeof(Func<,,>).MakeGenericType(typeof(object), typeof(object[]), returnType),
|
||||
// Expression.Convert(methodCall, returnType),
|
||||
// instanceParam,
|
||||
// argsParam
|
||||
// );
|
||||
|
||||
|
||||
//var resule = task.DynamicInvoke((object)[Activator.CreateInstance(type), [new DynamicContext(null)]]);
|
||||
return lambda.Compile();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static bool IsGenericTask(Type returnType, out Type taskResult)
|
||||
{
|
||||
// 判断是否为 Task 类型或泛型 Task<T>
|
||||
if (returnType == typeof(Task))
|
||||
{
|
||||
taskResult = null;
|
||||
return true;
|
||||
}
|
||||
else if (returnType.IsGenericType && returnType.GetGenericTypeDefinition() == typeof(Task<>))
|
||||
{
|
||||
// 获取泛型参数类型
|
||||
Type genericArgument = returnType.GetGenericArguments()[0];
|
||||
taskResult = genericArgument;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
taskResult = null;
|
||||
return false;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public static Delegate AutoCreate(Type type, MethodInfo methodInfo)
|
||||
{
|
||||
Type returnType = methodInfo.ReturnType;
|
||||
var parameterTypes = methodInfo.GetParameters().Select(p => p.ParameterType).ToArray();
|
||||
var parameterCount = parameterTypes.Length;
|
||||
|
||||
if (returnType == typeof(void))
|
||||
{
|
||||
if (parameterCount == 0)
|
||||
{
|
||||
// 无返回值,无参数
|
||||
return MethodCaller(type, methodInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 无返回值,有参数
|
||||
return MethodCaller(type, methodInfo, parameterTypes);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (parameterCount == 0)
|
||||
{
|
||||
// 有返回值,无参数
|
||||
return MethodCallerHaveResult(type, methodInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 有返回值,有参数
|
||||
return MethodCallerHaveResult(type, methodInfo, parameterTypes);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,7 @@ namespace Serein.Library.Utils
|
||||
/// 已完成注入的实例集合
|
||||
/// </summary>
|
||||
private readonly ConcurrentDictionary<string, object> _dependencies;
|
||||
private readonly ConcurrentDictionary<string, object[]> _registerParameterss;
|
||||
|
||||
/// <summary>
|
||||
/// 未完成注入的实例集合。
|
||||
@@ -40,9 +41,10 @@ namespace Serein.Library.Utils
|
||||
|
||||
public SereinIOC()
|
||||
{
|
||||
// 首先注册自己
|
||||
_dependencies = new ConcurrentDictionary<string, object>();
|
||||
_registerParameterss = new ConcurrentDictionary<string, object[]>();
|
||||
_typeMappings = new ConcurrentDictionary<string, Type>();
|
||||
|
||||
_unfinishedDependencies = new ConcurrentDictionary<string, List<(object, PropertyInfo)>>();
|
||||
}
|
||||
|
||||
@@ -57,7 +59,7 @@ namespace Serein.Library.Utils
|
||||
/// <param name="parameters">参数</param>
|
||||
public bool Register(Type type, params object[] parameters)
|
||||
{
|
||||
return RegisterType(type?.FullName, type);
|
||||
return RegisterType(type?.FullName, type, parameters);
|
||||
}
|
||||
/// <summary>
|
||||
/// 注册类型
|
||||
@@ -67,7 +69,7 @@ namespace Serein.Library.Utils
|
||||
public bool Register<T>(params object[] parameters)
|
||||
{
|
||||
var type = typeof(T);
|
||||
return RegisterType(type.FullName, type);
|
||||
return RegisterType(type.FullName, type, parameters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -78,7 +80,7 @@ namespace Serein.Library.Utils
|
||||
public bool Register<TService, TImplementation>(params object[] parameters)
|
||||
where TImplementation : TService
|
||||
{
|
||||
return RegisterType(typeof(TService).FullName, typeof(TImplementation));
|
||||
return RegisterType(typeof(TService).FullName, typeof(TImplementation), parameters);
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -132,6 +134,12 @@ namespace Serein.Library.Utils
|
||||
}
|
||||
public object Get(Type type)
|
||||
{
|
||||
var instance = Get(type.FullName);
|
||||
if(instance is null)
|
||||
{
|
||||
Console.WriteLine("类型没有注册:" + type.FullName);
|
||||
}
|
||||
|
||||
return Get(type.FullName);
|
||||
}
|
||||
|
||||
@@ -170,6 +178,7 @@ namespace Serein.Library.Utils
|
||||
disposable?.Dispose();
|
||||
}
|
||||
}
|
||||
_registerParameterss?.Clear();
|
||||
_unfinishedDependencies?.Clear();
|
||||
_typeMappings?.Clear();
|
||||
_dependencies?.Clear();
|
||||
@@ -185,11 +194,13 @@ namespace Serein.Library.Utils
|
||||
public string Name { get; set; }
|
||||
public Type Type { get; set; }
|
||||
}
|
||||
|
||||
private const string FlowBaseClassName = "<>$FlowBaseClass!@#";
|
||||
public Dictionary<string, List<string>> BuildDependencyTree()
|
||||
{
|
||||
var dependencyMap = new Dictionary<string, List<string>>();
|
||||
|
||||
//var tmpTypeFullName = new HashSet<string>();
|
||||
//var tmpTypeFullName2 = new HashSet<string>();
|
||||
dependencyMap[FlowBaseClassName] = new List<string>();
|
||||
foreach (var typeMapping in _typeMappings)
|
||||
{
|
||||
var constructor = GetConstructorWithMostParameters(typeMapping.Value); // 获取参数最多的构造函数
|
||||
@@ -198,18 +209,41 @@ namespace Serein.Library.Utils
|
||||
var parameters = constructor.GetParameters()
|
||||
.Select(p => p.ParameterType)
|
||||
.ToList();
|
||||
//if(parameters.Count == 0)
|
||||
//{
|
||||
// if (!dependencyMap.ContainsKey(typeMapping.Value.FullName))
|
||||
// {
|
||||
// dependencyMap[typeMapping.Value.FullName] = new List<string>();
|
||||
// }
|
||||
// dependencyMap[typeMapping.Value.FullName].Add(typeMapping.Key);
|
||||
//}
|
||||
|
||||
foreach (var param in parameters)
|
||||
|
||||
if(parameters .Count > 0)
|
||||
{
|
||||
if (!dependencyMap.ContainsKey(param.FullName))
|
||||
// 从类型的构造函数中提取类型
|
||||
foreach (var param in parameters)
|
||||
{
|
||||
dependencyMap[param.FullName] = new List<string>();
|
||||
if (!dependencyMap.ContainsKey(param.FullName))
|
||||
{
|
||||
dependencyMap[param.FullName] = new List<string>();
|
||||
}
|
||||
dependencyMap[param.FullName].Add(typeMapping.Key);
|
||||
//tmpTypeFullName.Add(param.FullName);
|
||||
//if (tmpTypeFullName2.Contains(param.FullName))
|
||||
//{
|
||||
// tmpTypeFullName2.Remove(param.FullName);
|
||||
//}
|
||||
}
|
||||
dependencyMap[param.FullName].Add(typeMapping.Key);
|
||||
}
|
||||
else
|
||||
{
|
||||
var type = typeMapping.Value;
|
||||
dependencyMap[FlowBaseClassName].Add(type.FullName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return dependencyMap;
|
||||
}
|
||||
// 获取参数最多的构造函数
|
||||
@@ -288,29 +322,44 @@ namespace Serein.Library.Utils
|
||||
|
||||
public object CreateInstance(string typeName)
|
||||
{
|
||||
if (_typeMappings.TryGetValue(typeName, out var type))
|
||||
if (!_typeMappings.TryGetValue(typeName, out var type))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (_dependencies.TryGetValue(typeName, out var instance))
|
||||
{
|
||||
return instance;
|
||||
}
|
||||
if (_registerParameterss.TryGetValue(typeName,out var @params))
|
||||
{
|
||||
instance = Activator.CreateInstance(type, @params);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 没有显示指定构造函数入参,选择参数最多的构造函数
|
||||
var constructor = GetConstructorWithMostParameters(type);
|
||||
var parameters = constructor.GetParameters();
|
||||
var args = new object[parameters.Length];
|
||||
|
||||
|
||||
for (int i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
var argType = parameters[i].ParameterType;
|
||||
var fullName = parameters[i].ParameterType.FullName;
|
||||
if (!_dependencies.TryGetValue(fullName, out var argObj))
|
||||
{
|
||||
argObj = CreateInstance(parameters[i].ParameterType.FullName);
|
||||
if (!_typeMappings.ContainsKey(fullName))
|
||||
{
|
||||
_typeMappings.TryAdd(fullName, argType);
|
||||
}
|
||||
argObj = CreateInstance(fullName);
|
||||
}
|
||||
args[i] = argObj;
|
||||
}
|
||||
var value = Activator.CreateInstance(type, args);
|
||||
InjectDependencies(value); // 完成创建后注入实例需要的特性依赖项
|
||||
|
||||
return value;
|
||||
instance = Activator.CreateInstance(type, args);
|
||||
}
|
||||
|
||||
return null;
|
||||
InjectDependencies(instance); // 完成创建后注入实例需要的特性依赖项
|
||||
_dependencies[typeName] = instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
||||
@@ -330,6 +379,10 @@ namespace Serein.Library.Utils
|
||||
continue;
|
||||
}
|
||||
var value = CreateInstance(typeName);
|
||||
if(value is null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
_dependencies[typeName] = value;
|
||||
OnIOCMembersChanged.Invoke(new IOCMembersChangedEventArgs(typeName, value));
|
||||
}
|
||||
@@ -349,11 +402,15 @@ namespace Serein.Library.Utils
|
||||
/// </summary>
|
||||
/// <param name="typeFull"></param>
|
||||
/// <param name="type"></param>
|
||||
private bool RegisterType(string typeFull, Type type)
|
||||
private bool RegisterType(string typeFull, Type type, params object[] parameters)
|
||||
{
|
||||
if (!_typeMappings.ContainsKey(typeFull))
|
||||
{
|
||||
_typeMappings[typeFull] = type;
|
||||
if(parameters.Length > 0)
|
||||
{
|
||||
_registerParameterss[typeFull] = parameters;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
@@ -432,15 +489,8 @@ namespace Serein.Library.Utils
|
||||
public void Run<T>(Action<T> action)
|
||||
{
|
||||
var service = Get<T>();
|
||||
if (service == null)
|
||||
{
|
||||
throw new Exception("类型没有注册:"+typeof(T).FullName);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
action(service);
|
||||
}
|
||||
action(service);
|
||||
|
||||
}
|
||||
|
||||
public void Run<T1, T2>(Action<T1, T2> action)
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Serein.Library.Utils
|
||||
{
|
||||
//public abstract class SerinExpressionEvaluator
|
||||
//{
|
||||
// public abstract string Evaluate(string expression ,object obj , out bool isChange);
|
||||
//}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Serein.Library.Utils
|
||||
{
|
||||
public class NodeRunCts : CancellationTokenSource
|
||||
{
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user