重写了节点的view、viewmodel关系,实现了对画布元素的选取功能,重构了底层依赖,添加了对net .Framework4.6.1以上的Framework类库支持

This commit is contained in:
fengjiayi
2024-09-12 20:32:54 +08:00
parent ec6e09ced1
commit f286fc644a
120 changed files with 91218 additions and 761 deletions

View File

@@ -0,0 +1,606 @@
using SqlSugar;
using System.ComponentModel;
using System.Net.Sockets;
using System.Reflection;
namespace Serein.DbSql
{
public enum DBSyncStart
{
/// <summary>
/// 无需同步
/// </summary>
[Description("无需同步")]
NotNeed,
/// <summary>
/// 同步成功
/// </summary>
[Description("同步成功")]
SyncSuccess,
/// <summary>
/// 同步失败
/// </summary>
[Description("同步失败")]
SyncFailure,
/// <summary>
/// 连接异常
/// </summary>
[Description("配置/连接异常")]
NetworkError,
/// <summary>
/// 没有同步事件
/// </summary>
[Description("没有同步事件,请使用 DBSync.SetSyncDataEvent() 方法设置同步事件")]
NoEvent,
}
public enum DBSyncExType
{
[Description("连接异常")]
ConnectError,
[Description("读写异常")]
CrudError,
[Description("同步异常")]
SyncError,
}
public class DBSyncConfig
{
public DBSyncConfig(ConnectionConfig primaryDBConfig,
ConnectionConfig secondaryDBConfig)
{
PrimaryDBConfig = primaryDBConfig;
SecondaryDBConfig = secondaryDBConfig;
}
/// <summary>
/// 主数据库IP
/// </summary>
//private string Host { get; }
/// <summary>
/// 主数据库端口
/// </summary>
//private int Port { get; }
/// <summary>
/// 主数据库配置
/// </summary>
private ConnectionConfig PrimaryDBConfig { get; }
/// <summary>
/// 从数据库配置
/// </summary>
private ConnectionConfig SecondaryDBConfig { get; }
public override string ToString()
{
return $"[主数据库配置]{PrimaryDBConfig.ConnectionString}" + Environment.NewLine +
$"[从数据库配置]{SecondaryDBConfig.ConnectionString}" + Environment.NewLine;
}
/// <summary>
/// 检查网络状态
/// </summary>
/// <returns></returns>
public bool GetNetworkState()
{
var isOpen = DBSync.IsPortOpen(); // 数据库基类获取网络状态
if (!isOpen)
{
DBSync.SetIsNeedSyncData(true); // 远程数据库查询失败,尝试本地数据库
}
return isOpen;
}
/// <summary>
/// 返回从数据库
/// </summary>
/// <returns></returns>
public SqlSugarClient GetSecondaryDB()
{
DBSync.SyncEvent.Wait();
return new SqlSugarClient(SecondaryDBConfig);
}
/// <summary>
/// 返回主数据库
/// </summary>
/// <returns></returns>
/// <exception cref="DBSyncException"></exception>
public SqlSugarClient GetPrimaryDB()
{
try
{
// 等待同步事件
DBSync.SyncEvent.Wait();
// 检查主数据库连接状态
if (!DBSync.IsPortOpen()) // 返回主数据库检测网络状态
{
// Console.WriteLine($"主数据库无法连接IP:{IP},端口:{Port}");
DBSync.SetIsNeedSyncData(true); // 网络不可达
return null;
}
// 检查是否需要同步数据
/*if (DBSync.GetIsNeedSyncData())
{
var syncState = DBSync.StartSyncDataBase();
if (syncState != DBSyncStart.SyncSuccess && syncState != DBSyncStart.NotNeed)
{
// Console.WriteLine($"获取读写客户端前,尝试同步时发生异常:{DBSync.GetDescription(syncState)}");
return null;
}
}*/
// 返回主数据库客户端
return new SqlSugarClient(PrimaryDBConfig);
}
catch // (Exception ex)
{
// Console.WriteLine($"发生异常:{ex.Message}");
return null;
}
}
}
/// <summary>
/// 数据库同步异常
/// </summary>
public class DBSyncException : Exception
{
public DBSyncExType ExceptionType { get; private set; }
public DBSyncException(DBSyncExType exceptionType)
{
ExceptionType = exceptionType;
}
public DBSyncException(DBSyncExType exceptionType, string message) : base(message)
{
ExceptionType = exceptionType;
}
public DBSyncException(DBSyncExType exceptionType, string message, Exception innerException) : base(message, innerException)
{
ExceptionType = exceptionType;
}
public override string ToString()
{
return $"异常: {ExceptionType}: {GetDescription(ExceptionType)}. Message: {Message}";
}
public static string GetDescription(DBSyncExType value)
{
FieldInfo field = value.GetType().GetField(value.ToString());
DescriptionAttribute attribute = (DescriptionAttribute)field.GetCustomAttribute(typeof(DescriptionAttribute));
return attribute == null ? value.ToString() : attribute.Description;
}
}
/// <summary>
/// 远程、本地数据库同步
/// </summary>
public static class DBSync
{
/// <summary>
/// 主数据库配置
/// </summary>
private static ConnectionConfig PrimaryConfig { get; set; }
/// <summary>
/// 从数据库配置
/// </summary>
private static ConnectionConfig SecondaryConfig { get; set; }
/// <summary>
/// 主数据库IP
/// </summary>
private static string Host { get; set; }
/// <summary>
/// 主数据库端口
/// </summary>
private static int Port { get; set; }
/// <summary>
/// 同步数据事件(远程数据库,本地数据库,是否执行成功)
/// </summary>
private static Func<SqlSugarClient, SqlSugarClient, bool> SyncDataEvent { get; set; }
private static Action<bool> StateChangeEvent { get; set; }
/// <summary>
/// 数据库设置锁
/// </summary>
//private static object DBSetLock { get; set; } = new object();
/// <summary>
/// 是否需要同步数据
/// </summary>
private static bool IsNeedSyncData { get; set; } = false;
/// <summary>
/// 等待次数执行了多少次操作后才尝试进行同步设置为0容易影响性能
/// </summary>
private static int WaitCount { get; set; } = 10;
/// <summary>
/// 客户端获取计数
/// </summary>
private static int CrudDBGetCount { get; set; } = 0;
/// <summary>
/// 同步端获取计数
/// </summary>
private static int SyncDBGetCount { get; set; } = 0;
//public static ManualResetEventSlim SyncEvent { get; } = new ManualResetEventSlim(true); // 同步事件
/// <summary>
/// 远程本地同步阻塞事件
/// </summary>
public static FifoManualResetEvent SyncEvent { get; } = new FifoManualResetEvent(true);
/// <summary>
/// 数据同步锁
/// </summary>
private static object SyncLock { get; } = new object();
/// <summary>
/// 是否需要同步数据读写锁
/// </summary>
private static readonly ReaderWriterLockSlim NeedSyncStateLock = new ReaderWriterLockSlim();
/// <summary>
/// 是否断开过,true=断开过false=没有断开过
/// 设置为 false 时自动检测网络情况,只有在网络正常的情况下才能成功设置为 true
/// </summary>
/// <param name="value"></param>
public static void SetIsNeedSyncData(bool value)
{
if (value == IsNeedSyncData)
{
return;
}
//Console.WriteLine("变更数据库");
// 写入锁
NeedSyncStateLock.EnterWriteLock();
try
{
if (value)
{
IsNeedSyncData = true;
return;
}
IsNeedSyncData = !IsPortOpen(); // 变更 是否同步 属性时获取网络状态
}
finally
{
NeedSyncStateLock.ExitWriteLock();
StateChangeEvent?.Invoke(IsNeedSyncData);
}
}
public static bool GetIsNeedSyncData()
{
// 读取锁
NeedSyncStateLock.EnterReadLock();
try
{
return IsNeedSyncData; //是否需要同步数据
}
finally
{
NeedSyncStateLock.ExitReadLock();
}
}
/// <summary>
/// 配置主数据库
/// </summary>
public static void PrimaryConnect(DbType dbType, string host, int port, string dbName, string user, string password)
{
Host = host;
Port = port;
PrimaryConfig = GetConnectionConfig(dbType, host, port.ToString(), dbName, user, password);
/*SyncEvent.Wait();
if (true || IsPortOpen(host, port))
{
// 目标端口打通时才会更改数据库配置
lock (DBSetLock)
{
Host = host;
Port = port;
PrimaryConfig = GetConnectionConfig(dbType, host, port.ToString(), dbName, user, password);
}
}
else
{
throw new DBSyncException(DBSyncExType.ConnectError, $"主数据库配置失败无法连接目标配置IP:{host},端口:{port},目标库名:{dbName},账户:{user}");
}*/
}
/// <summary>
/// 配置从数据库
/// </summary>
public static void SecondaryConnect(DbType dbType, string host, int port, string dbName, string user, string password)
{
SecondaryConfig = GetConnectionConfig(dbType, host, port.ToString(), dbName, user, password);
/*if (IsPortOpen(host, port))
{
lock (DBSetLock)
{
SecondaryConfig = GetConnectionConfig(dbType, host, port.ToString(), dbName, user, password);
}
}
else
{
throw new DBSyncException(DBSyncExType.ConnectError, $"从数据库配置失败,无法连接,目标配置:{host},端口:{port},目标库名:{dbName},账户:{user}");
}*/
}
/// <summary>
/// 尝试执行一次数据同步
/// </summary>
public static bool SyncData()
{
SetIsNeedSyncData(true);
var state = StartSyncDataBase(true); // 手动同步
return state == DBSyncStart.SyncSuccess || state == DBSyncStart.NotNeed;
}
/// <summary>
/// 设置同步事件与等待次数。
/// </summary>
/// <param name="syncDataEvent">同步事件(需要手动同步数据)</param>
/// <param name="waitCount">等待次数执行了多少次操作后才尝试进行同步设置为0容易影响性能</param>
public static void SetSyncEvent(Func<SqlSugarClient, SqlSugarClient, bool> syncDataEvent, int waitCount = 0)
{
SyncDataEvent = syncDataEvent;
WaitCount = waitCount;
}
/// <summary>
/// 设置状态变化事件
/// </summary>
/// <param name="stateChangeEvent"></param>
/// <param name="isAtOnce"></param>
public static void SetStateChangeEvent(Action<bool> stateChangeEvent)
{
StateChangeEvent = stateChangeEvent;
}
/// <summary>
/// 获取数据库配置不推荐使用在除了Repository的地方外部调用
/// </summary>
/// <returns></returns>
public static DBSyncConfig GetSyncSqlConfig()
{
/*SyncEvent.Wait();
*/
if (GetIsNeedSyncData())
{
_ = Task.Run(() => StartSyncDataBase()); // new了一个RepositoryBase时尝试同步数据
}
lock (SyncLock)
{
CrudDBGetCount++;
//Console.WriteLine($"获取客户端:{CrudDBGetCount}");
return new DBSyncConfig(PrimaryConfig, SecondaryConfig);
}
}
public static void ReSetCrudDb()
{
CrudDBGetCount--;
Task.Run(() => StartSyncDataBase()); // 释放数据库连接时尝试同步数据
/*if (GetIsNeedSyncData())
{
}*/
// Console.WriteLine($"释放客户端:{CrudDBGetCount}");
}
public static DBSyncStart StartSyncDataBase(bool isAtOnce = false)
{
/*if (!isAtOnce && WaitCount > 0)
{
WaitCount--;
return DBSyncStart.NotNeed;
}*/
SyncEvent.Reset(); // 锁定线程,保证只有一个线程进入该方法
if (!GetIsNeedSyncData())
{
SyncEvent.Set();
return DBSyncStart.NotNeed;
}
if (!IsPortOpen()) // 同步时获取网络状态
{
SetIsNeedSyncData(true);
SyncEvent.Set();
return DBSyncStart.NetworkError;
}
if (SyncDataEvent == null)
{
SyncEvent.Set();
return DBSyncStart.NoEvent;
}
lock (SyncLock) // 同步锁,避免其它符合进入条件的线程执行多次同步
{
if (!GetIsNeedSyncData())
{
SyncEvent.Set();
return DBSyncStart.NotNeed;
}
Console.WriteLine("网络检测OK准备同步数据");
try
{
bool isSuccess = SyncDataEvent.Invoke(new SqlSugarClient(PrimaryConfig), new SqlSugarClient(SecondaryConfig));
SetIsNeedSyncData(!isSuccess);
if (isSuccess)
{
return DBSyncStart.SyncSuccess;
}
else
{
return DBSyncStart.SyncFailure;
}
}
catch (Exception ex)
{
// 记录异常日志
Console.WriteLine($"同步数据时发生异常: {ex.Message}");
return DBSyncStart.SyncFailure;
}
finally
{
SyncEvent.Set(); // 释放同步事件,以防止其他线程一直被阻塞
}
}
}
public static string GetDescription(DBSyncStart value)
{
FieldInfo field = value.GetType().GetField(value.ToString());
DescriptionAttribute attribute = (DescriptionAttribute)field.GetCustomAttribute(typeof(DescriptionAttribute));
return attribute == null ? value.ToString() : attribute.Description;
}
/// <summary>
/// 检测目标地址是否打通
/// </summary>
/// <param name="ip">ip地址</param>
/// <param name="port">端口号</param>
/// <param name="timeout">超时时间</param>
/// <returns></returns>
public static bool IsPortOpen(string ip, int port, int timeout = 300)
{
using (var client = new TcpClient())
{
var result = client.ConnectAsync(ip, port);
try
{
var open = result.Wait(timeout);
return open;
}
catch (SocketException)
{
return false;
}
}
}
/// <summary>
/// 检测目标地址是否打通主数据库IP和端口是否打通true通false断)
/// </summary>
/// <param name="timeout">超时时间</param>
/// <returns></returns>
public static bool IsPortOpen(int timeout = 300)
{
string ip = Host;
int port = Port;
using (var client = new TcpClient())
{
bool isOpen = true;
try
{
var result = client.ConnectAsync(ip, port);
isOpen = result.Wait(timeout);
if (!isOpen)
{
//Console.WriteLine($"连接超时{ip},{port}");
}
return isOpen;
}
catch
{
isOpen = false;
return isOpen;
}
finally
{
//Console.WriteLine("网络检测:" + isOpen);
}
}
}
/// <summary>
/// 返回数据库连接串
/// </summary>
/// <param name="dbType">数据库类型</param>
/// <param name="host">服务器IP地址</param>
/// <param name="dbName">数据库名</param>
/// <param name="name">登录账户</param>
/// <param name="password">登录密码</param>
private static ConnectionConfig GetConnectionConfig(DbType dbType, string host, string port, string dbName, string name, string password)
{
ConnectionConfig config;
string ConnectionString;
switch (dbType)
{
case DbType.MySql:
ConnectionString = $"Server={host};DataBase={dbName};Port={port};UserId={name};Password={password};Persist Security Info=True;Allow Zero Datetime=True;Character Set=utf8;";
config = new ConnectionConfig()
{
ConnectionString = ConnectionString,//连接符字串
DbType = DbType.MySql,
IsAutoCloseConnection = true,
InitKeyType = InitKeyType.Attribute //从实体特性中读取主键自增列信息
};
break;
case DbType.SqlServer:
ConnectionString = $"Server={host},{port};DataBase={dbName};uid={name};pwd={password}";
config = new ConnectionConfig()
{
ConnectionString = ConnectionString,//连接符字串
DbType = DbType.SqlServer,
IsAutoCloseConnection = true,
InitKeyType = InitKeyType.Attribute //从实体特性中读取主键自增列信息
};
break;
default:
config = null;
break;
}
return config;
}
}
}

View File

@@ -0,0 +1,71 @@
namespace Serein.DbSql
{
/// <summary>
/// 线程阻塞
/// </summary>
public class FifoManualResetEvent
{
private readonly object lockObj = new object();
/// <summary>
/// 让线程按进入时间顺序调用
/// </summary>
private readonly Queue<Thread> waitQueue = new Queue<Thread>();
private bool isSet;
public bool IsSet { get => isSet; set => isSet = value; }
public FifoManualResetEvent(bool initialState = false)
{
IsSet = initialState;
}
/// <summary>
/// 等待解锁
/// </summary>
public void Wait()
{
lock (lockObj)
{
if (IsSet)
{
// 获取到了发送的信号,线程开始重新执行
return;
}
var currentThread = Thread.CurrentThread;
waitQueue.Enqueue(currentThread);
while (!IsSet || waitQueue.Peek() != currentThread)
{
Monitor.Wait(lockObj);
}
waitQueue.Dequeue();
}
}
/// <summary>
/// 发送信号
/// </summary>
public void Set()
{
lock (lockObj)
{
IsSet = true;
Monitor.PulseAll(lockObj);
}
}
/// <summary>
/// 锁定当前线程
/// </summary>
public void Reset()
{
lock (lockObj)
{
IsSet = false;
}
}
}
}

View File

@@ -0,0 +1,19 @@
using System.Linq.Expressions;
namespace Serein.DbSql
{
public interface IRepositoryBase<TEntity> where TEntity : class, new()
{
TEntity GetModelByID(dynamic ID);
int Add(TEntity Model);
int Update(TEntity Model);
bool DeleteByID(dynamic ID);
bool Delete(Expression<Func<TEntity, bool>> where);
int UpdateColumns(TEntity model, Expression<Func<TEntity, object>> expression);
}
}

View File

@@ -0,0 +1,877 @@
using Serein.DbSql;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json;
using SqlSugar;
using System.Data;
using System.Linq.Expressions;
using Serein.Tool;
namespace Serein.Helper
{
// public class RepositoryBase<TEntity> : DataBase, IRepositoryBase<TEntity> where TEntity : class, new()
public class RepositoryBase<TEntity> : IRepositoryBase<TEntity> where TEntity : class, new()
{
public bool isHaveErr;
public string ErrMsg = "";
public string filterName = "SubSystemName";
~RepositoryBase()
{
DBSync.ReSetCrudDb();
}
public RepositoryBase()
{
}
/// <summary>
/// 是否优先使用本地数据库
/// </summary>
public bool IsUseLoaclDB = false;
#region
#region
/// <summary>
/// 无状态数据操作(查询)泛型抽象方法
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="func"></param>
/// <returns></returns>
/// <exception cref="DBSyncException"></exception>
public virtual T SyncExecuteRead<T>(Func<SqlSugarClient, T> func)
{
var syncSqlConfig = DBSync.GetSyncSqlConfig(); // 基类获取数据库配置
if (IsUseLoaclDB)
{
var secondaryDB = syncSqlConfig.GetSecondaryDB();
return func.Invoke(secondaryDB); // 尝试查询本地数据库
}
if (syncSqlConfig.GetNetworkState()) // 网络检测
{
try
{
var primaryDB = syncSqlConfig.GetPrimaryDB();
if (primaryDB != null)
{
return func.Invoke(primaryDB); // 尝试查询本地数据库
}
else
{
Console.WriteLine("远程数据库不可用");
}
}
catch(Exception ex)
{
DBSync.SetIsNeedSyncData(true); // 网络不可达
Console.WriteLine(ex.ToString());
}
}
try
{
var secondaryDB = syncSqlConfig.GetSecondaryDB();
return func.Invoke(secondaryDB); // 尝试查询本地数据库
}
catch
{
throw new DBSyncException(DBSyncExType.CrudError, $"主从数据库不可用。\r\n {syncSqlConfig.ToString()} ");
}
}
/// <summary>
/// 无状态数据操作(查询)泛型抽象方法
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="func"></param>
/// <returns></returns>
/// <exception cref="DBSyncException"></exception>
public virtual T SyncExecuteRead<T>(Func<SimpleClient<TEntity>, T> func)
{
var syncSqlConfig = DBSync.GetSyncSqlConfig(); // 基类获取数据库配置
if (IsUseLoaclDB)
{
var secondaryDB = syncSqlConfig.GetSecondaryDB().GetSimpleClient<TEntity>();
return func.Invoke(secondaryDB); // 尝试查询本地数据库
}
if (syncSqlConfig.GetNetworkState()) // 网络检测
{
try
{
var primaryDB = syncSqlConfig.GetPrimaryDB()?.GetSimpleClient<TEntity>();
if (primaryDB != null)
{
return func.Invoke(primaryDB); // 尝试查询远程数据库
}
else
{
Console.WriteLine("远程数据库不可用");
}
}
catch (Exception ex)
{
DBSync.SetIsNeedSyncData(true); // 网络不可达
Console.WriteLine(ex.ToString());
}
}
try
{
var secondaryDB = syncSqlConfig.GetSecondaryDB().GetSimpleClient<TEntity>();
return func.Invoke(secondaryDB); // 尝试查询本地数据库
}
catch
{
throw new DBSyncException(DBSyncExType.CrudError, $"主从数据库不可用。\r\n {syncSqlConfig.ToString()} ");
}
}
#endregion
#region
/* /// <summary>
/// 无状态数据操作(查询)泛型抽象方法
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="func"></param>
/// <returns></returns>
/// <exception cref="DBSyncException"></exception>
public virtual T ExecuteSyncOperation<T>(Func<SqlSugarClient, T> func)
{
DBSync.SyncEvent.Wait();
var secondaryDB = SyncSqlConfig.GetSecondaryDB();
try
{
return func.Invoke(secondaryDB); // 优先尝试查询本地数据库
}
catch
{
try
{
var primaryDB = SyncSqlConfig.GetPrimaryDB();
if (primaryDB != null)
{
if (SyncSqlConfig.GetNetworkState()) // 网络检测
{
DBSync.SyncEvent.Wait();
return func.Invoke(primaryDB); // 尝试查询远程数据库
}
else
{
throw new DBSyncException(DBSyncExType.CrudError, "网络不可达,无法查询远程数据库。");
}
}
else
{
throw new DBSyncException(DBSyncExType.CrudError, "远程数据库不可用。");
}
}
catch
{
throw new DBSyncException(DBSyncExType.CrudError, $"远程数据库查询失败。\r\n {SyncSqlConfig.ToString()} ");
}
}
}
/// <summary>
/// 无状态数据操作(查询)泛型抽象方法
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="func"></param>
/// <returns></returns>
/// <exception cref="DBSyncException"></exception>
public virtual T ExecuteSyncOperation<T>(Func<SimpleClient<TEntity>, T> func)
{
DBSync.SyncEvent.Wait();
var secondaryDB = SyncSqlConfig.GetSecondaryDB().GetSimpleClient<TEntity>();
try
{
return func.Invoke(secondaryDB); // 优先尝试查询本地数据库
}
catch
{
// 本地数据库查询失败,尝试远程数据库
try
{
var primaryDB = SyncSqlConfig.GetPrimaryDB()?.GetSimpleClient<TEntity>();
if (primaryDB != null)
{
if (SyncSqlConfig.GetNetworkState()) // 网络检测
{
DBSync.SyncEvent.Wait();
return func.Invoke(primaryDB); // 尝试查询远程数据库
}
else
{
throw new DBSyncException(DBSyncExType.CrudError, "网络不可达,无法查询远程数据库。");
}
}
else
{
throw new DBSyncException(DBSyncExType.CrudError, "远程数据库不可用。");
}
}
catch
{
throw new DBSyncException(DBSyncExType.CrudError, $"远程数据库查询失败。\r\n {SyncSqlConfig.ToString()} ");
}
}
}
*/
#endregion
#region
/// <summary>
/// 有状态数据操作更新、增加、删除泛型抽象方法优先操作本地数据库操作远程数据库失败时调用DBSync.SetIsNeedSyncData(true);
/// </summary>
/// <typeparam name="TResult"></typeparam>
/// <param name="primaryFunc"></param>
/// <param name="secondaryFunc"></param>
/// <returns></returns>
/// <exception cref="DBSyncException"></exception>
public virtual T SyncExecuteCUD<T>(Func<SqlSugarClient, T> func)
{
var syncSqlConfig = DBSync.GetSyncSqlConfig(); // 基类获取数据库配置
var secondaryDB = syncSqlConfig.GetSecondaryDB();
try
{
var secondaryResult = func.Invoke(secondaryDB); // 本地数据库操作
if (IsUseLoaclDB)
{
return secondaryResult;
}
if (syncSqlConfig.GetNetworkState()) // 网络检测
{
var primaryDB = syncSqlConfig.GetPrimaryDB();
if(primaryDB != null)
{
var primaryResult = func.Invoke(primaryDB); // 远程数据库操作
return primaryResult;
}
else
{
Console.WriteLine("远程数据库不可用");
}
}
return secondaryResult;
}
catch (Exception ex)
{
Console.WriteLine("主从数据库不可用:" + ex.ToString());
DBSync.SetIsNeedSyncData(true);
throw new DBSyncException(DBSyncExType.CrudError, $"主从数据库不可用。\r\n {syncSqlConfig.ToString()} ");
}
}
public virtual T SyncExecuteCUD<T>(Func<SimpleClient<TEntity>, T> func)
{
var syncSqlConfig = DBSync.GetSyncSqlConfig(); // 基类获取数据库配置
var secondaryDB = syncSqlConfig.GetSecondaryDB().GetSimpleClient<TEntity>();
try
{
var secondaryResult = func.Invoke(secondaryDB); // 本地数据库操作
if (IsUseLoaclDB)
{
return secondaryResult;
}
if (syncSqlConfig.GetNetworkState()) // 网络检测
{
var primaryDB = syncSqlConfig.GetPrimaryDB().GetSimpleClient<TEntity>();
if(primaryDB != null)
{
var primaryResult = func.Invoke(primaryDB); // 远程数据库操作
return primaryResult;
}
else
{
Console.WriteLine("远程数据库不可用");
}
}
return secondaryResult;
}
catch (Exception ex)
{
Console.WriteLine("主从数据库不可用:" + ex.ToString());
DBSync.SetIsNeedSyncData(true);
throw new DBSyncException(DBSyncExType.CrudError, $"主从数据库不可用。\r\n {syncSqlConfig.ToString()} ");
}
}
#endregion
public TEntity SyncRead(Func<SqlSugarClient, TEntity> func)
{
return SyncExecuteRead(func);
}
public bool SyncRead(Func<SqlSugarClient, bool> func)
{
return SyncExecuteRead(func);
}
public List<T> SyncRead<T>(Func<SqlSugarClient, List<T>> func)
{
return SyncExecuteRead(func);
}
/// <summary>
/// 查询返回实体
/// </summary>
public TEntity SyncRead(Func<SimpleClient<TEntity>, TEntity> func)
{
return SyncExecuteRead(func);
}
/// <summary>
/// 查询返回实体列表
/// </summary>
public List<T> SyncRead<T>(Func<SimpleClient<TEntity>, List<T>> func)
{
return SyncExecuteRead(func);
}
public TEntity SyncCUD(Func<SqlSugarClient, TEntity> func)
{
return SyncExecuteCUD(func);
}
public int SyncCUD(Func<SqlSugarClient, int> func)
{
return SyncExecuteCUD(func);
}
public bool SyncCUD(Func<SqlSugarClient, bool> func)
{
return SyncExecuteCUD(func);
}
public TEntity SyncSimpleCUD(Func<SimpleClient<TEntity>, TEntity> func)
{
return SyncExecuteCUD(func);
}
public int SyncSimpleCUD(Func<SimpleClient<TEntity>, int> func)
{
return SyncExecuteCUD(func);
}
public bool SyncSimpleCUD(Func<SimpleClient<TEntity>, bool> func)
{
return SyncExecuteCUD(func);
}
#endregion
public virtual TEntity GetModelByID(dynamic ID)
{
return SyncRead(db => db.GetById(ID));
}
public virtual TEntity GetModel(Expression<Func<TEntity, bool>> where)
{
try
{
return SyncRead(db => db.Queryable<TEntity>().Where(where).First()); //db.GetSingle(where));
// GetSingle结果不能大于1
}
catch (Exception ex)
{
isHaveErr = true;
ErrMsg = ex.Message;
return null;
}
}
public virtual int Add(TEntity model)
{
try
{
return SyncCUD(db => db.Insertable(model).ExecuteCommand());
}
catch (Exception ex)
{
isHaveErr = true;
ErrMsg = ex.Message;
return 0;
}
}
public virtual int AddAndReturnIndex(TEntity model)
{
try
{
return SyncCUD(db => db.Insertable(model).ExecuteReturnIdentity());
}
catch (Exception ex)
{
isHaveErr = true;
ErrMsg = ex.Message;
return 0;
}
}
public virtual bool Exist(Expression<Func<TEntity, bool>> where)
{
try
{
return SyncRead(db => db.Queryable<TEntity>().Where(where).Take(1).Any());
}
catch (Exception ex)
{
isHaveErr = true;
ErrMsg = ex.Message;
return false;
}
}
public int AddOrUpdate(TEntity model, string keyValue)
{
if (keyValue == "")
{
try
{
return SyncCUD(db => db.Insertable(model).ExecuteCommand());
}
catch (Exception ex)
{
isHaveErr = true;
ErrMsg = ex.Message;
return 0;
}
}
return SyncCUD(db => db.Updateable(model).ExecuteCommand());
}
public virtual int Update(TEntity model)
{
return SyncCUD(db => db.Updateable(model).ExecuteCommand());
}
public virtual int UpdateColumns(TEntity model, Expression<Func<TEntity, object>> expression)
{
//DatabaseSync.StartcaControls();
try
{
return SyncCUD(db => db.Updateable(model).UpdateColumns(expression).ExecuteCommand());
}
catch (Exception ex)
{
isHaveErr = true;
ErrMsg = ex.Message;
return 0;
}
}
public virtual bool DeleteByID(dynamic ID)
{
//SyncCUD(db => db.Updateable<TEntity>().RemoveDataCache().ExecuteCommand());
return SyncSimpleCUD(db => (bool)db.DeleteById(ID));
}
public virtual bool Delete(Expression<Func<TEntity, bool>> where)
{
return SyncSimpleCUD(db => db.Delete(where));
}
public virtual string GetPageList(Pagination pagination, Expression<Func<TEntity, bool>> where = null)
{
//DatabaseSync.StartcaControls();
return new
{
rows = GetList(pagination, where),
total = pagination.total,
page = pagination.page,
records = pagination.records
}.ToJson();
}
public virtual TEntity GetSingle(Expression<Func<TEntity, bool>> expression)
{
//DatabaseSync.StartcaControls();
return SyncRead(db => db.Queryable<TEntity>().Filter(filterName, isDisabledGobalFilter: true).Single(expression));
}
public virtual List<TEntity> GetTop(int Top, Expression<Func<TEntity, object>> expression, OrderByType _OrderByType = OrderByType.Asc, Expression<Func<TEntity, bool>> where = null, string selstr = "*")
{
return SyncRead(db => db.Queryable<TEntity>().Select(selstr).WhereIF(where != null, where)
.Take(Top)
.OrderBy(expression, _OrderByType)
.Filter(filterName, isDisabledGobalFilter: true)
.ToList());
}
/// <summary>
/// 排序表达式所用的键,排序方式,搜索条件
/// </summary>
/// <param name="OrderExpression"></param>
/// <param name="_OrderByType"></param>
/// <param name="where"></param>
/// <returns></returns>
public virtual TEntity GetFirst(Expression<Func<TEntity, object>> OrderExpression, OrderByType _OrderByType = OrderByType.Asc, Expression<Func<TEntity, bool>> where = null)
{
return SyncRead(db => db.Queryable<TEntity>().Filter(filterName, isDisabledGobalFilter: true).WhereIF(where != null, where)
.OrderBy(OrderExpression, _OrderByType)
.First());
}
public virtual List<TEntity> GetList(Pagination pagination, Expression<Func<TEntity, bool>> where = null)
{
int totalNumber = 0;
List<TEntity> result = SyncRead(db => db.Queryable<TEntity>().WhereIF(where != null, where).OrderBy(pagination.sidx + " " + pagination.sord)
.Filter(filterName, isDisabledGobalFilter: true)
.ToPageList(pagination.page, pagination.rows, ref totalNumber));
pagination.records = totalNumber;
return result;
}
public virtual List<TEntity> GetList(Expression<Func<TEntity, bool>> where = null)
{
return SyncRead(db => db.Queryable<TEntity>().WhereIF(where != null, where).Filter(filterName, isDisabledGobalFilter: true)
.ToList());
}
public virtual List<TEntity> GetList()
{
return SyncRead(db => db.Queryable<TEntity>().ToList());
}
public virtual DataTable GetDataTable(Expression<Func<TEntity, bool>> where = null, Pagination pagination = null)
{
if (pagination != null)
{
return DataHelper.ListToDataTable(GetList(pagination, where));
}
return DataHelper.ListToDataTable(GetList(where));
}
public virtual void UseFilter(SqlFilterItem item)
{
SyncCUD(db =>
{
db.QueryFilter.Remove(item.FilterName);
db.QueryFilter.Add(item);
return 0;
});
filterName = item.FilterName;
}
public virtual void ClearFilter()
{
SyncCUD(db =>
{
db.QueryFilter.Clear();
return 0;
});
filterName = null;
}
/* public void ReSetConnStr(string constr, SqlSugar.DbType _dbtype)
{
db = DBHelper.CreateDB(constr, _dbtype);
Sclient = db.GetSimpleClient<TEntity>();
}
public virtual TEntity GetModelByID(dynamic ID)
{
return Sclient.GetById(ID);
}
public virtual TEntity GetModel(Expression<Func<TEntity, bool>> where)
{
try
{
return Sclient.GetSingle(where);
}
catch (Exception ex)
{
isHaveErr = true;
ErrMsg = ex.Message;
return null;
}
}
public virtual int Add(TEntity model)
{
try
{
return db.Insertable(model).ExecuteCommand();
}
catch (Exception ex)
{
isHaveErr = true;
ErrMsg = ex.Message;
return 0;
}
}
public virtual int AddAndReturnIndex(TEntity model)
{
try
{
return db.Insertable(model).ExecuteReturnIdentity();
}
catch (Exception ex)
{
isHaveErr = true;
ErrMsg = ex.Message;
return 0;
}
}
public virtual bool Exist(Expression<Func<TEntity, bool>> where)
{
return db.Queryable<TEntity>().Where(where).Take(1).Any();
}
public int AddOrUpdate(TEntity model, string Keyvale)
{
if (Keyvale == "")
{
return db.Insertable(model).ExecuteCommand();
}
return db.Updateable(model).ExecuteCommand();
}
public virtual int Update(TEntity model)
{
return db.Updateable(model).ExecuteCommand();
}
public virtual int UpdateColumns(TEntity model, Expression<Func<TEntity, object>> expression)
{
return db.Updateable(model).UpdateColumns(expression).ExecuteCommand();
}
public virtual bool DeleteByID(dynamic ID)
{
db.Updateable<TEntity>().RemoveDataCache().ExecuteCommand();
return Sclient.DeleteById(ID);
}
public virtual bool Delete(Expression<Func<TEntity, bool>> where)
{
return Sclient.Delete(where);
}
public virtual string GetPageList(Pagination pagination, Expression<Func<TEntity, bool>> where = null)
{
return new
{
rows = GetList(pagination, where),
total = pagination.total,
page = pagination.page,
records = pagination.records
}.ToJson();
}
public virtual TEntity GetSingle(Expression<Func<TEntity, bool>> expression)
{
return db.Queryable<TEntity>().Filter(filterName, isDisabledGobalFilter: true).Single(expression);
}
public virtual List<TEntity> GetTop(int Top, Expression<Func<TEntity, object>> expression, OrderByType _OrderByType = OrderByType.Asc, Expression<Func<TEntity, bool>> where = null, string selstr = "*")
{
return db.Queryable<TEntity>().Select(selstr).WhereIF(where != null, where)
.Take(Top)
.OrderBy(expression, _OrderByType)
.Filter(filterName, isDisabledGobalFilter: true)
.ToList();
}
public virtual TEntity GetFirst(Expression<Func<TEntity, object>> OrderExpression, OrderByType _OrderByType = OrderByType.Asc, Expression<Func<TEntity, bool>> where = null)
{
return db.Queryable<TEntity>().Filter(filterName, isDisabledGobalFilter: true).WhereIF(where != null, where)
.OrderBy(OrderExpression, _OrderByType)
.First();
}
public virtual List<TEntity> GetList(Pagination pagination, Expression<Func<TEntity, bool>> where = null)
{
int totalNumber = 0;
List<TEntity> result = db.Queryable<TEntity>().WhereIF(where != null, where).OrderBy(pagination.sidx + " " + pagination.sord)
.Filter(filterName, isDisabledGobalFilter: true)
.ToPageList(pagination.page, pagination.rows, ref totalNumber);
pagination.records = totalNumber;
return result;
}
public virtual List<TEntity> GetList(Expression<Func<TEntity, bool>> where = null)
{
return db.Queryable<TEntity>().WhereIF(where != null, where).Filter(filterName, isDisabledGobalFilter: true)
.ToList();
}
public virtual List<TEntity> GetList()
{
return db.Queryable<TEntity>().ToList();
}
public virtual DataTable GetDataTable(Expression<Func<TEntity, bool>> where = null, Pagination pagination = null)
{
if (pagination != null)
{
return DataHelper.ListToDataTable(GetList(pagination, where));
}
return DataHelper.ListToDataTable(GetList(where));
}
public virtual void UseFilter(SqlFilterItem item)
{
db.QueryFilter.Remove(item.FilterName);
db.QueryFilter.Add(item);
filterName = item.FilterName;
}
public virtual void ClearFilter()
{
db.QueryFilter.Clear();
filterName = null;
}
public void BeginTran()
{
db.Ado.BeginTran();
}
public void CommitTran()
{
db.Ado.CommitTran();
}
public void RollbackTran()
{
db.Ado.RollbackTran();
}*/
}
public class Pagination
{
/// <summary>
/// 每页行数
/// </summary>
public int rows { get; set; }
/// <summary>
/// 当前页
/// </summary>
public int page { get; set; }
/// <summary>
/// /排序列
/// </summary>
public string sidx { get; set; }
/// <summary>
/// 排序类型
/// </summary>
public string sord { get; set; }
/// <summary>
/// 总记录数
/// </summary>
public int records { get; set; }
/// <summary>
/// 总页数
/// </summary>
public int total
{
get
{
if (records > 0)
{
if (records % rows != 0)
{
return records / rows + 1;
}
return records / rows;
}
return 0;
}
}
}
}

13
Library.Core/Flow/Api.cs Normal file
View File

@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Serein.Flow
{
public interface IDynamicFlowNode
{
}
}

View File

@@ -0,0 +1,73 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Serein.Flow
{
public enum DynamicNodeType
{
/// <summary>
/// 初始化
/// </summary>
Init,
/// <summary>
/// 开始载入
/// </summary>
Loading,
/// <summary>
/// 结束
/// </summary>
Exit,
/// <summary>
/// 触发器
/// </summary>
Flipflop,
/// <summary>
/// 条件节点
/// </summary>
Condition,
/// <summary>
/// 动作节点
/// </summary>
Action,
}
/// <summary>
/// 用来判断一个类是否需要注册并构建实例(单例模式场景使用)
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class DynamicFlowAttribute(bool scan = true) : Attribute
{
public bool Scan { get; set; } = scan;
}
/// <summary>
/// 标记一个方法是什么类型加载dll后用来拖拽到画布中
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class MethodDetailAttribute(DynamicNodeType methodDynamicType,
string methodTips = "",
bool scan = true,
string lockName = "") : Attribute
{
public bool Scan { get; set; } = scan;
public string MethodTips { get; } = methodTips;
public DynamicNodeType MethodDynamicType { get; } = methodDynamicType;
public string LockName { get; } = lockName;
}
/// <summary>
/// 是否为显式参数
/// </summary>
[AttributeUsage(AttributeTargets.Parameter)]
public class ExplicitAttribute : Attribute // where TEnum : Enum
{
}
}

View File

@@ -0,0 +1,168 @@
using DynamicDemo.Node;
using Serein.Library.IOC;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using static System.Collections.Specialized.BitVector32;
using static System.Runtime.InteropServices.JavaScript.JSType;
namespace Serein.Flow
{
public enum FfState
{
Succeed,
Cancel,
}
/// <summary>
/// 触发器上下文
/// </summary>
public class FlipflopContext
{
public FfState State { get; set; }
public object? Data { get; set; }
/*public FlipflopContext()
{
State = FfState.Cancel;
}*/
public FlipflopContext(FfState ffState,object? data = null)
{
State = ffState;
Data = data;
}
}
/// <summary>
/// 动态流程上下文
/// </summary>
public class DynamicContext(IServiceContainer serviceContainer)
{
private readonly string contextGuid = "";//System.Guid.NewGuid().ToString();
public IServiceContainer ServiceContainer { get; } = serviceContainer;
private List<Type> InitServices { get; set; } = [];
// private ConcurrentDictionary<string, object?> ContextData { get; set; } = [];
//public void SetFlowData(object data)
//{
// var threadId = Thread.CurrentThread.ManagedThreadId.ToString();
// var name = $"{threadId}.{contextGuid}FlowData";
// SetData(name,data);
//}
//public object GetFlowData(bool IsRetain = false)
//{
// var threadId = Thread.CurrentThread.ManagedThreadId.ToString();
// var name = $"{threadId}.{contextGuid}FlowData";
// if (IsRetain)
// {
// return GetData(name);
// }
// else
// {
// return GetAndRemoteData(name);
// }
//}
public void InitService<T>()
{
InitService(typeof(T));
}
public void InitService(Type type)
{
if (!InitServices.Contains(type))
{
InitServices.Add(type);
}
else
{
//throw new Exception("初始化时试图添加已存在的类型:"+type.Name);
Console.WriteLine("初始化时试图添加已存在的类型:" + type.Name);
}
}
public void Biuld()
{
foreach (var item in InitServices)
{
ServiceContainer.Register(item);
}
ServiceContainer.Build();
}
//public object? RemoveData(string key)
//{
// if (ContextData.Remove(key, out var data))
// {
// return data;
// }
// return null;
//}
//public void SetData<T>(string key, T value)
//{
// ContextData[key] = value;
//}
//public T? GetData<T>(string key)
//{
// if (ContextData.TryGetValue(key, out object? value))
// {
// if(value == null)
// {
// return default;
// }
// if (value.GetType() == typeof(T))
// {
// return (T)value;
// }
// }
// return default;
//}
//public object? GetData(string key)
//{
// if (ContextData.TryGetValue(key, out object? value))
// {
// return value;
// }
// return null;
//}
//public ConcurrentDictionary<string,Task> FlipFlopTasks { get; set; } = [];
public NodeRunTcs NodeRunCts { get; set; }
public Task CreateTimingTask(Action action, int time = 100, int count = -1)
{
NodeRunCts ??= ServiceContainer.Get<NodeRunTcs>();
return Task.Factory.StartNew(async () =>
{
for(int i = 0; i < count; i++)
{
NodeRunCts.Token.ThrowIfCancellationRequested();
await time;
action.Invoke();
}
});
}
}
public static class MyExtensions
{
public static TaskAwaiter GetAwaiter(this int i) => Task.Delay(i).GetAwaiter();
}
// if (time <= 0) throw new ArgumentException("时间不能≤0");
}

View File

@@ -0,0 +1,240 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static Dm.net.buffer.ByteArrayBuffer;
namespace Serein.Flow
{
/// <summary>
/// 显式参数
/// </summary>
public class ExplicitData
{
/// <summary>
/// 索引
/// </summary>
public int Index { get; set; }
/// <summary>
/// 是否为显式参数
/// </summary>
public bool IsExplicitData { get; set; }
/// <summary>
/// 显式类型
/// </summary>
public Type? ExplicitType { get; set; }
/// <summary>
/// 显示类型编号>
/// </summary>
public string ExplicitTypeName { get; set; }
/// <summary>
/// 方法需要的类型
/// </summary>
public Type DataType { get; set; }
/// <summary>
/// 方法入参参数名称
/// </summary>
public string ParameterName { get; set; }
/// <summary>
/// 入参值
/// </summary>
public string DataValue { get; set; }
public string[] Items { get; set; }
public ExplicitData Clone() => new()
{
Index = Index,
IsExplicitData = IsExplicitData,
ExplicitType = ExplicitType,
DataType = DataType,
ParameterName = ParameterName,
ExplicitTypeName = ExplicitTypeName,
DataValue = string.IsNullOrEmpty(DataValue) ? string.Empty : DataValue,
Items = [.. Items],
};
}
public class MethodDetails
{
public MethodDetails Clone()
{
return new MethodDetails
{
ActingInstance = ActingInstance,
ActingInstanceType = ActingInstanceType,
MethodDelegate = MethodDelegate,
MethodDynamicType = MethodDynamicType,
MethodGuid = Guid.NewGuid().ToString(),
MethodTips = MethodTips ,
ReturnType = ReturnType,
MethodName = MethodName,
MethodLockName = MethodLockName,
ExplicitDatas = ExplicitDatas.Select(it => it.Clone()).ToArray(),
};
}
/// <summary>
/// 作用实例
/// </summary>
public Type ActingInstanceType { get; set; }
/// <summary>
/// 作用实例
/// </summary>
public object ActingInstance { get; set; }
/// <summary>
/// 方法GUID
/// </summary>
public string MethodGuid { get; set; }
/// <summary>
/// 方法名称
/// </summary>
public string MethodName { get; set; }
/// <summary>
/// 方法委托
/// </summary>
public Delegate MethodDelegate { get; set; }
/// <summary>
/// 节点类型
/// </summary>
public DynamicNodeType MethodDynamicType { get; set; }
/// <summary>
/// 锁名称
/// </summary>
public string MethodLockName { get; set; }
/// <summary>
/// 方法说明
/// </summary>
public string MethodTips { get; set; }
/// <summary>
/// 参数内容
/// </summary>
public ExplicitData[] ExplicitDatas { get; set; }
/// <summary>
/// 出参类型
/// </summary>
public Type ReturnType { get; set; }
public bool IsCanConnect(Type returnType)
{
if (ExplicitDatas.Length == 0)
{
// 目标不需要传参,可以舍弃结果?
return true;
}
var types = ExplicitDatas.Select(it => it.DataType).ToArray();
// 检查返回类型是否是元组类型
if (returnType.IsGenericType && IsValueTuple(returnType))
{
return CompareGenericArguments(returnType, types);
}
else
{
int index = 0;
if (types[index] == typeof(DynamicContext))
{
index++;
if (types.Length == 1)
{
return true;
}
}
// 被连接节点检查自己需要的参数类型,与发起连接的节点比较返回值类型
if (returnType == types[index])
{
return true;
}
}
return false;
}
/// <summary>
/// 检查元组类型
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
private bool IsValueTuple(Type type)
{
if (!type.IsGenericType) return false;
var genericTypeDef = type.GetGenericTypeDefinition();
return genericTypeDef == typeof(ValueTuple<>) ||
genericTypeDef == typeof(ValueTuple<,>) ||
genericTypeDef == typeof(ValueTuple<,,>) ||
genericTypeDef == typeof(ValueTuple<,,,>) ||
genericTypeDef == typeof(ValueTuple<,,,,>) ||
genericTypeDef == typeof(ValueTuple<,,,,,>) ||
genericTypeDef == typeof(ValueTuple<,,,,,,>) ||
genericTypeDef == typeof(ValueTuple<,,,,,,,>);
}
private bool CompareGenericArguments(Type returnType, Type[] parameterTypes)
{
var genericArguments = returnType.GetGenericArguments();
var length = parameterTypes.Length;
for (int i = 0; i < genericArguments.Length; i++)
{
if (i >= length) return false;
if (IsValueTuple(genericArguments[i]))
{
// 如果当前参数也是 ValueTuple递归检查嵌套的泛型参数
if (!CompareGenericArguments(genericArguments[i], parameterTypes.Skip(i).ToArray()))
{
return false;
}
}
else if (genericArguments[i] != parameterTypes[i])
{
return false;
}
}
return true;
}
}
}

View File

@@ -0,0 +1,171 @@
using Serein.Flow;
using Serein.Flow.NodeModel;
using Serein.Flow.Tool;
using Serein.Library.Http;
using Serein.Library.IOC;
using SqlSugar;
namespace DynamicDemo.Node
{
public class NodeRunTcs: CancellationTokenSource
{
}
public class NodeFlowStarter(IServiceContainer serviceContainer,List<MethodDetails> methodDetails)
{
private readonly IServiceContainer ServiceContainer = serviceContainer;
private readonly List<MethodDetails> methodDetails = methodDetails;
private Action ExitAction = null;
private DynamicContext context = null;
public NodeRunTcs MainCts;
/// <summary>
/// 运行测试
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
//public async Task RunAsync1(List<NodeBase> nodes)
//{
// await Task.Run(async ()=> await StartRunAsync(nodes));
//}
public async Task RunAsync(List<NodeBase> nodes)
{
var startNode = nodes.FirstOrDefault(p => p.IsStart);
if (startNode == null) { return; }
context = new(ServiceContainer);
MainCts = ServiceContainer.CreateServiceInstance<NodeRunTcs>();
var initMethods = methodDetails.Where(it => it.MethodDynamicType == DynamicNodeType.Init).ToList();
var loadingMethods = methodDetails.Where(it => it.MethodDynamicType == DynamicNodeType.Loading).ToList();
var exitMethods = methodDetails.Where(it => it.MethodDynamicType == DynamicNodeType.Exit).ToList();
ExitAction = () =>
{
ServiceContainer.Run<WebServer>((web) =>
{
web?.Stop();
});
foreach (MethodDetails? md in exitMethods)
{
object?[]? args = [context];
object?[]? data = [md.ActingInstance, args];
md.MethodDelegate.DynamicInvoke(data);
}
if(context != null && context.NodeRunCts != null && !context.NodeRunCts.IsCancellationRequested)
{
context.NodeRunCts.Cancel();
}
if (MainCts!=null && !MainCts.IsCancellationRequested) MainCts.Cancel();
ServiceContainer.Reset();
};
foreach (var md in initMethods) // 初始化 - 调用方法
{
//md.ActingInstance = context.ServiceContainer.Get(md.ActingInstanceType);
object?[]? args = [context];
object?[]? data = [md.ActingInstance, args];
md.MethodDelegate.DynamicInvoke(data);
}
context.Biuld();
foreach (var md in loadingMethods) // 加载
{
//md.ActingInstance = context.ServiceContainer.Get(md.ActingInstanceType);
object?[]? args = [context];
object?[]? data = [md.ActingInstance, args];
md.MethodDelegate.DynamicInvoke(data);
}
var flipflopNodes = nodes.Where(it => it.MethodDetails?.MethodDynamicType == DynamicNodeType.Flipflop
&& it.PreviousNodes.Count == 0
&& it.IsStart != true).ToArray();
var singleFlipflopNodes = flipflopNodes.Select(it => (SingleFlipflopNode)it).ToArray();
// 使用 TaskCompletionSource 创建未启动的任务
var tasks = singleFlipflopNodes.Select(async node =>
{
await FlipflopExecute(node);
}).ToArray();
try
{
await Task.WhenAll([startNode.ExecuteStack(context),.. tasks]);
}
catch (Exception ex)
{
await Console.Out.WriteLineAsync(ex.ToString());
}
}
private async Task FlipflopExecute(SingleFlipflopNode singleFlipFlopNode)
{
DynamicContext context = new DynamicContext(ServiceContainer);
MethodDetails md = singleFlipFlopNode.MethodDetails;
try
{
if (!DelegateCache.GlobalDicDelegates.TryGetValue(md.MethodName, out Delegate del))
{
return;
}
var func = md.ExplicitDatas.Length == 0 ? ((Func<object, object, Task<FlipflopContext>>)del) : ((Func<object, object[], Task<FlipflopContext>>)del);
while (!MainCts.IsCancellationRequested) // 循环中直到栈为空才会退出
{
object?[]? parameters = singleFlipFlopNode.GetParameters(context, md);
// 调用委托并获取结果
FlipflopContext flipflopContext = await func.Invoke(md.ActingInstance, parameters);
if (flipflopContext == null)
{
break;
}
else if (flipflopContext.State == FfState.Cancel)
{
break;
}
else if (flipflopContext.State == FfState.Succeed)
{
singleFlipFlopNode.FlowState = true;
singleFlipFlopNode.FlowData = flipflopContext.Data;
var tasks = singleFlipFlopNode.SucceedBranch.Select(nextNode =>
{
var context = new DynamicContext(ServiceContainer);
nextNode.PreviousNode = singleFlipFlopNode;
return nextNode.ExecuteStack(context);
}).ToArray();
Task.WaitAll(tasks);
}
}
}
catch (Exception ex)
{
await Console.Out.WriteLineAsync(ex.ToString());
}
}
public void Exit()
{
ExitAction?.Invoke();
}
}
}

View File

@@ -0,0 +1,51 @@
namespace Serein.Flow.NodeModel
{
/// <summary>
/// 组合动作节点(用于动作区域)
/// </summary>
public class CompositeActionNode : NodeBase
{
public List<SingleActionNode> ActionNodes;
/// <summary>
/// 组合动作节点(用于动作区域)
/// </summary>
public CompositeActionNode(List<SingleActionNode> actionNodes)
{
ActionNodes = actionNodes;
}
public void AddNode(SingleActionNode node)
{
ActionNodes.Add(node);
MethodDetails ??= node.MethodDetails;
}
//public override void Execute(DynamicContext context)
//{
// //Dictionary<int,object> dict = new Dictionary<int,object>();
// for (int i = 0; i < ActionNodes.Count; i++)
// {
// SingleActionNode? action = ActionNodes[i];
// try
// {
// action.Execute(context);
// }
// catch (Exception ex)
// {
// Debug.Write(ex.Message);
// return;
// }
// }
// CurrentState = true;
// return;
// /*foreach (var nextNode in TrueBranchNextNodes)
// {
// nextNode.ExecuteStack(context);
// }*/
//}
}
}

View File

@@ -0,0 +1,67 @@
namespace Serein.Flow.NodeModel
{
/// <summary>
/// 组合条件节点(用于条件区域)
/// </summary>
public class CompositeConditionNode : NodeBase
{
public List<SingleConditionNode> ConditionNodes { get; } =[];
public void AddNode(SingleConditionNode node)
{
ConditionNodes.Add(node);
MethodDetails ??= node.MethodDetails;
}
public override object? Execute(DynamicContext context)
{
// bool allTrue = ConditionNodes.All(condition => Judge(context,condition.MethodDetails));
// bool IsAllTrue = true; // 初始化为 true
FlowState = true;
foreach (SingleConditionNode? node in ConditionNodes)
{
if (!Judge(context, node))
{
FlowState = false;
break;// 一旦发现条件为假,立即退出循环
}
}
return PreviousNode?.FlowData;
//if (IsAllTrue)
//{
// foreach (var nextNode in TrueBranchNextNodes)
// {
// nextNode.ExecuteStack(context);
// }
//}
//else
//{
// foreach (var nextNode in FalseBranchNextNodes)
// {
// nextNode.ExecuteStack(context);
// }
//}
}
private bool Judge(DynamicContext context, SingleConditionNode node)
{
try
{
node.Execute(context);
return node.FlowState;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return false;
}
}
}

View File

@@ -0,0 +1,6 @@
namespace Serein.Flow.NodeModel
{
public class CompositeLoopNode : NodeBase
{
}
}

View File

@@ -0,0 +1,510 @@
using Newtonsoft.Json;
using Serein.Flow.Tool;
namespace Serein.Flow.NodeModel
{
public enum ConnectionType
{
/// <summary>
/// 真分支
/// </summary>
IsSucceed,
/// <summary>
/// 假分支
/// </summary>
IsFail,
/// <summary>
/// 异常发生分支
/// </summary>
IsError,
/// <summary>
/// 上游分支(执行当前节点前会执行一次上游分支)
/// </summary>
Upstream,
}
/// <summary>
/// 节点基类(数据):条件控件,动作控件,条件区域,动作区域
/// </summary>
public abstract class NodeBase : IDynamicFlowNode
{
public MethodDetails MethodDetails { get; set; }
public string Guid { get; set; }
public string DisplayName { get; set; }
public bool IsStart { get; set; }
public string DelegateName { get; set; }
/// <summary>
/// 运行时的上一节点
/// </summary>
public NodeBase? PreviousNode { get; set; }
/// <summary>
/// 上一节点集合
/// </summary>
public List<NodeBase> PreviousNodes { get; set; } = [];
/// <summary>
/// 下一节点集合(真分支)
/// </summary>
public List<NodeBase> SucceedBranch { get; set; } = [];
/// <summary>
/// 下一节点集合(假分支)
/// </summary>
public List<NodeBase> FailBranch { get; set; } = [];
/// <summary>
/// 异常分支
/// </summary>
public List<NodeBase> ErrorBranch { get; set; } = [];
/// <summary>
/// 上游分支
/// </summary>
public List<NodeBase> UpstreamBranch { get; set; } = [];
/// <summary>
/// 当前状态(进入真分支还是假分支,异常分支在异常中确定)
/// </summary>
public bool FlowState { get; set; } = true;
//public ConnectionType NextType { get; set; } = ConnectionType.IsTrue;
/// <summary>
/// 当前传递数据
/// </summary>
public object? FlowData { get; set; } = null;
// 正常流程节点调用
public virtual object? Execute(DynamicContext context)
{
MethodDetails md = MethodDetails;
object? result = null;
if (DelegateCache.GlobalDicDelegates.TryGetValue(md.MethodName, out Delegate del))
{
if (md.ExplicitDatas.Length == 0)
{
if (md.ReturnType == typeof(void))
{
((Action<object>)del).Invoke(md.ActingInstance);
}
else
{
result = ((Func<object, object>)del).Invoke(md.ActingInstance);
}
}
else
{
object?[]? parameters = GetParameters(context, MethodDetails);
if (md.ReturnType == typeof(void))
{
((Action<object, object[]>)del).Invoke(md.ActingInstance, parameters);
}
else
{
result = ((Func<object, object[], object>)del).Invoke(md.ActingInstance, parameters);
}
}
// context.SetFlowData(result);
// CurrentData = result;
}
return result;
}
// 触发器调用
public virtual async Task<object?> ExecuteAsync(DynamicContext context)
{
MethodDetails md = MethodDetails;
object? result = null;
if (DelegateCache.GlobalDicDelegates.TryGetValue(md.MethodName, out Delegate del))
{
if (md.ExplicitDatas.Length == 0)
{
// 调用委托并获取结果
FlipflopContext flipflopContext = await ((Func<object, Task<FlipflopContext>>)del).Invoke(MethodDetails.ActingInstance);
if (flipflopContext != null)
{
if (flipflopContext.State == FfState.Cancel)
{
throw new Exception("this async task is cancel.");
}
else
{
if (flipflopContext.State == FfState.Succeed)
{
FlowState = true;
result = flipflopContext.Data;
}
else
{
FlowState = false;
}
}
}
}
else
{
object?[]? parameters = GetParameters(context, MethodDetails);
// 调用委托并获取结果
FlipflopContext flipflopContext = await ((Func<object, object[], Task<FlipflopContext>>)del).Invoke(MethodDetails.ActingInstance, parameters);
if (flipflopContext != null)
{
if (flipflopContext.State == FfState.Cancel)
{
throw new Exception("取消此异步");
}
else
{
FlowState = flipflopContext.State == FfState.Succeed;
result = flipflopContext.Data;
}
}
}
}
return result;
}
public async Task ExecuteStack(DynamicContext context)
{
await Task.Run(async () =>
{
await ExecuteStackTmp(context);
});
}
public async Task ExecuteStackTmp(DynamicContext context)
{
var cts = context.ServiceContainer.Get<CancellationTokenSource>();
Stack<NodeBase> stack =[];
stack.Push(this);
while (stack.Count > 0 && !cts.IsCancellationRequested) // 循环中直到栈为空才会退出循环
{
// 从栈中弹出一个节点作为当前节点进行处理
var currentNode = stack.Pop();
if (currentNode.MethodDetails != null)
{
currentNode.MethodDetails.ActingInstance ??= context.ServiceContainer.Get(MethodDetails.ActingInstanceType);
} // 设置方法执行的对象
// 获取上游分支,首先执行一次
var upstreamNodes = currentNode.UpstreamBranch;
for (int i = upstreamNodes.Count - 1; i >= 0; i--)
{
upstreamNodes[i].PreviousNode = currentNode;
await upstreamNodes[i].ExecuteStack(context);
}
if (currentNode.MethodDetails != null && currentNode.MethodDetails.MethodDynamicType == DynamicNodeType.Flipflop)
{
currentNode.FlowData = await currentNode.ExecuteAsync(context);
}
else
{
currentNode.FlowData = currentNode.Execute(context);
}
var nextNodes = currentNode.FlowState ? currentNode.SucceedBranch
: currentNode.FailBranch;
// 将下一个节点集合中的所有节点逆序推入栈中
for (int i = nextNodes.Count - 1; i >= 0; i--)
{
nextNodes[i].PreviousNode = currentNode;
stack.Push(nextNodes[i]);
}
}
}
public object[]? GetParameters(DynamicContext context, MethodDetails md)
{
// 用正确的大小初始化参数数组
var types = md.ExplicitDatas.Select(it => it.DataType).ToArray();
if (types.Length == 0)
{
return [md.ActingInstance];
}
object[]? parameters = new object[types.Length];
for (int i = 0; i < types.Length; i++)
{
var mdEd = md.ExplicitDatas[i];
Type type = mdEd.DataType;
var f1 = PreviousNode?.FlowData?.GetType();
var f2 = mdEd.DataType;
if (type == typeof(DynamicContext))
{
parameters[i] = context;
}
else if (type == typeof(MethodDetails))
{
parameters[i] = md;
}
else if (type == typeof(NodeBase))
{
parameters[i] = this;
}
else if (mdEd.IsExplicitData) // 显式参数
{
if (mdEd.DataType.IsEnum)
{
var enumValue = Enum.Parse(mdEd.DataType, mdEd.DataValue);
parameters[i] = enumValue;
}
else if (mdEd.ExplicitType == typeof(string))
{
parameters[i] = mdEd.DataValue;
}
else if (mdEd.ExplicitType == typeof(bool))
{
parameters[i] = bool.Parse(mdEd.DataValue);
}
else if (mdEd.ExplicitType == typeof(int))
{
parameters[i] = int.Parse(mdEd.DataValue);
}
else if (mdEd.ExplicitType == typeof(double))
{
parameters[i] = double.Parse(mdEd.DataValue);
}
else
{
parameters[i] = "";
//parameters[i] = ConvertValue(mdEd.DataValue, mdEd.ExplicitType);
}
}
else if ((f1 != null && f2 != null) && f2.IsAssignableFrom(f1) || f2.FullName.Equals(f1.FullName))
{
parameters[i] = PreviousNode?.FlowData;
}
else
{
var tmpParameter = PreviousNode?.FlowData?.ToString();
if (mdEd.DataType.IsEnum)
{
var enumValue = Enum.Parse(mdEd.DataType, tmpParameter);
parameters[i] = enumValue;
}
else if (mdEd.DataType == typeof(string))
{
parameters[i] = tmpParameter;
}
else if (mdEd.DataType == typeof(bool))
{
parameters[i] = bool.Parse(tmpParameter);
}
else if (mdEd.DataType == typeof(int))
{
parameters[i] = int.Parse(tmpParameter);
}
else if (mdEd.DataType == typeof(double))
{
parameters[i] = double.Parse(tmpParameter);
}
else
{
if (tmpParameter != null && mdEd.DataType!= null)
{
parameters[i] = ConvertValue(tmpParameter, mdEd.DataType);
}
}
}
}
return parameters;
}
private dynamic? ConvertValue(string value, Type targetType)
{
try
{
if (!string.IsNullOrEmpty(value))
{
return JsonConvert.DeserializeObject(value, targetType);
}
else
{
return null;
}
}
catch (JsonReaderException ex)
{
Console.WriteLine(ex);
return value;
}
catch (JsonSerializationException ex)
{
// 如果无法转为对应的JSON对象
int startIndex = ex.Message.IndexOf("to type '") + "to type '".Length; // 查找类型信息开始的索引
int endIndex = ex.Message.IndexOf('\''); // 查找类型信息结束的索引
var typeInfo = ex.Message[startIndex..endIndex]; // 提取出错类型信息,该怎么传出去?
Console.WriteLine("无法转为对应的JSON对象:"+typeInfo);
return null;
}
catch // (Exception ex)
{
return value;
}
}
#region ExecuteAsync调用方法
//public virtual async Task<object?> ExecuteAsync(DynamicContext context)
//{
// MethodDetails md = MethodDetails;
// object? result = null;
// if (DelegateCache.GlobalDicDelegates.TryGetValue(md.MethodName, out Delegate del))
// {
// if (md.ExplicitDatas.Length == 0)
// {
// if (md.ReturnType == typeof(void))
// {
// ((Action<object>)del).Invoke(md.ActingInstance);
// }
// else if (md.ReturnType == typeof(Task<FlipflopContext>))
// {
// // 调用委托并获取结果
// FlipflopContext flipflopContext = await ((Func<object, Task<FlipflopContext>>)del).Invoke(MethodDetails.ActingInstance);
// if (flipflopContext != null)
// {
// if (flipflopContext.State == FfState.Cancel)
// {
// throw new Exception("this async task is cancel.");
// }
// else
// {
// if (flipflopContext.State == FfState.Succeed)
// {
// CurrentState = true;
// result = flipflopContext.Data;
// }
// else
// {
// CurrentState = false;
// }
// }
// }
// }
// else
// {
// result = ((Func<object, object>)del).Invoke(md.ActingInstance);
// }
// }
// else
// {
// object?[]? parameters = GetParameters(context, MethodDetails);
// if (md.ReturnType == typeof(void))
// {
// ((Action<object, object[]>)del).Invoke(md.ActingInstance, parameters);
// }
// else if (md.ReturnType == typeof(Task<FlipflopContext>))
// {
// // 调用委托并获取结果
// FlipflopContext flipflopContext = await ((Func<object, object[], Task<FlipflopContext>>)del).Invoke(MethodDetails.ActingInstance, parameters);
// if (flipflopContext != null)
// {
// if (flipflopContext.State == FfState.Cancel)
// {
// throw new Exception("取消此异步");
// }
// else
// {
// CurrentState = flipflopContext.State == FfState.Succeed;
// result = flipflopContext.Data;
// }
// }
// }
// else
// {
// result = ((Func<object, object[], object>)del).Invoke(md.ActingInstance, parameters);
// }
// }
// context.SetFlowData(result);
// }
// return result;
//}
#endregion
}
}
/* while (stack.Count > 0) // 循环中直到栈为空才会退出
{
// 从栈中弹出一个节点作为当前节点进行处理
var currentNode = stack.Pop();
if(currentNode is CompositeActionNode || currentNode is CompositeConditionNode)
{
currentNode.currentState = true;
}
else if (currentNode is CompositeConditionNode)
{
}
currentNode.Execute(context);
// 根据当前节点的执行结果选择下一节点集合
// 如果 currentState 为真,选择 TrueBranchNextNodes否则选择 FalseBranchNextNodes
var nextNodes = currentNode.currentState ? currentNode.TrueBranchNextNodes
: currentNode.FalseBranchNextNodes;
// 将下一个节点集合中的所有节点逆序推入栈中
for (int i = nextNodes.Count - 1; i >= 0; i--)
{
stack.Push(nextNodes[i]);
}
}*/

View File

@@ -0,0 +1,68 @@
namespace Serein.Flow.NodeModel
{
/// <summary>
/// 单动作节点(用于动作控件)
/// </summary>
public class SingleActionNode : NodeBase
{
//public override void Execute(DynamicContext context)
//{
// try
// {
// Execute(context, base.MethodDetails);
// CurrentState = true;
// }
// catch (Exception ex)
// {
// Debug.Write(ex.Message);
// CurrentState = false;
// }
//}
//public void Execute(DynamicContext context, MethodDetails md)
//{
// if (DelegateCache.GlobalDicDelegates.TryGetValue(md.MethodName, out Delegate del))
// {
// object? result = null;
// if (md.ExplicitDatas.Length == 0)
// {
// if (md.ReturnType == typeof(void))
// {
// ((Action<object>)del).Invoke(md.ActingInstance);
// }
// else
// {
// result = ((Func<object, object>)del).Invoke(md.ActingInstance);
// }
// }
// else
// {
// object?[]? parameters = GetParameters(context, MethodDetails);
// if (md.ReturnType == typeof(void))
// {
// ((Action<object, object[]>)del).Invoke(md.ActingInstance, parameters);
// }
// else
// {
// result = ((Func<object, object[], object>)del).Invoke(md.ActingInstance, parameters);
// }
// }
// // 根据 ExplicitDatas.Length 判断委托类型
// //var action = (Action<object, object[]>)del;
// // 调用委托并获取结果
// // action.Invoke(MethodDetails.ActingInstance, parameters);
// //parameters = [md.ActingInstance, "", 123, ""];
// context.SetFlowData(result);
// }
//}
}
}

View File

@@ -0,0 +1,71 @@
using Serein.Flow.SerinExpression;
namespace Serein.Flow.NodeModel
{
/// <summary>
/// 条件节点(用于条件控件)
/// </summary>
public class SingleConditionNode : NodeBase
{
/// <summary>
/// 是否为自定义参数
/// </summary>
public bool IsCustomData { get; set; }
/// <summary>
/// 自定义参数值
/// </summary>
public object? CustomData { get; set; }
/// <summary>
/// 条件表达式
/// </summary>
public string Expression { get; set; }
public override object? Execute(DynamicContext context)
{
// 接收上一节点参数or自定义参数内容
object? result;
if (IsCustomData)
{
result = CustomData;
}
else
{
result = PreviousNode?.FlowData;
}
FlowState = SerinConditionParser.To(result, Expression);
Console.WriteLine($"{result} {Expression} -> " + FlowState);
return result;
}
//public override void Execute(DynamicContext context)
//{
// CurrentState = Judge(context, base.MethodDetails);
//}
//private bool Judge(DynamicContext context, MethodDetails md)
//{
// try
// {
// if (DelegateCache.GlobalDicDelegates.TryGetValue(md.MethodName, out Delegate del))
// {
// object[] parameters = GetParameters(context, md);
// var temp = del.DynamicInvoke(parameters);
// //context.GetData(GetDyPreviousKey());
// return (bool)temp;
// }
// }
// catch (Exception ex)
// {
// Debug.Write(ex.Message);
// }
// return false;
//}
}
}

View File

@@ -0,0 +1,35 @@
using Serein.Flow.SerinExpression;
namespace Serein.Flow.NodeModel
{
/// <summary>
/// Expression Operation - 表达式操作
/// </summary>
public class SingleExpOpNode : NodeBase
{
/// <summary>
/// 表达式
/// </summary>
public string Expression { get; set; }
public override object? Execute(DynamicContext context)
{
var data = PreviousNode?.FlowData;
var newData = SerinExpressionEvaluator.Evaluate(Expression, data, out bool isChange);
FlowState = true;
Console.WriteLine(newData);
if (isChange)
{
return newData;
}
else
{
return PreviousNode?.FlowData;
}
}
}
}

View File

@@ -0,0 +1,12 @@
namespace Serein.Flow.NodeModel
{
public class SingleFlipflopNode : NodeBase
{
public override object Execute(DynamicContext context)
{
throw new NotImplementedException("无法以非await/async的形式调用触发器");
}
}
}

View File

@@ -0,0 +1,337 @@
using System;
using System.Reflection;
using System.Runtime.InteropServices;
namespace Serein.Flow.SerinExpression
{
public abstract class ConditionResolver
{
public abstract bool Evaluate(object obj);
}
public class PassConditionResolver : ConditionResolver
{
public Operator Op { get; set; }
public override bool Evaluate(object obj)
{
return Op switch
{
Operator.Pass => true,
Operator.NotPass => false,
_ => throw new NotSupportedException("不支持的条件类型")
};
}
public enum Operator
{
Pass,
NotPass,
}
}
public class ValueTypeConditionResolver<T> : ConditionResolver where T : struct, IComparable<T>
{
public enum Operator
{
/// <summary>
/// 不进行任何操作
/// </summary>
Node,
/// <summary>
/// 大于
/// </summary>
GreaterThan,
/// <summary>
/// 小于
/// </summary>
LessThan,
/// <summary>
/// 等于
/// </summary>
Equal,
/// <summary>
/// 大于或等于
/// </summary>
GreaterThanOrEqual,
/// <summary>
/// 小于或等于
/// </summary>
LessThanOrEqual,
/// <summary>
/// 在两者之间
/// </summary>
InRange,
/// <summary>
/// 不在两者之间
/// </summary>
OutOfRange
}
public Operator Op { get; set; }
public T Value { get; set; }
public T RangeStart { get; set; }
public T RangeEnd { get; set; }
public string ArithmeticExpression { get; set; }
public override bool Evaluate(object obj)
{
if (obj is T typedObj)
{
double numericValue = Convert.ToDouble(typedObj);
if (!string.IsNullOrEmpty(ArithmeticExpression))
{
numericValue = SerinArithmeticExpressionEvaluator.Evaluate(ArithmeticExpression, numericValue);
}
T evaluatedValue = (T)Convert.ChangeType(numericValue, typeof(T));
return Op switch
{
Operator.GreaterThan => evaluatedValue.CompareTo(Value) > 0,
Operator.LessThan => evaluatedValue.CompareTo(Value) < 0,
Operator.Equal => evaluatedValue.CompareTo(Value) == 0,
Operator.GreaterThanOrEqual => evaluatedValue.CompareTo(Value) >= 0,
Operator.LessThanOrEqual => evaluatedValue.CompareTo(Value) <= 0,
Operator.InRange => evaluatedValue.CompareTo(RangeStart) >= 0 && evaluatedValue.CompareTo(RangeEnd) <= 0,
Operator.OutOfRange => evaluatedValue.CompareTo(RangeStart) < 0 || evaluatedValue.CompareTo(RangeEnd) > 0,
_ => throw new NotSupportedException("不支持的条件类型")
};
/* switch (Op)
{
case Operator.GreaterThan:
return evaluatedValue.CompareTo(Value) > 0;
case Operator.LessThan:
return evaluatedValue.CompareTo(Value) < 0;
case Operator.Equal:
return evaluatedValue.CompareTo(Value) == 0;
case Operator.GreaterThanOrEqual:
return evaluatedValue.CompareTo(Value) >= 0;
case Operator.LessThanOrEqual:
return evaluatedValue.CompareTo(Value) <= 0;
case Operator.InRange:
return evaluatedValue.CompareTo(RangeStart) >= 0 && evaluatedValue.CompareTo(RangeEnd) <= 0;
case Operator.OutOfRange:
return evaluatedValue.CompareTo(RangeStart) < 0 || evaluatedValue.CompareTo(RangeEnd) > 0;
}*/
}
return false;
}
}
public class BoolConditionResolver : ConditionResolver
{
public enum Operator
{
/// <summary>
/// 是
/// </summary>
Is
}
public Operator Op { get; set; }
public bool Value { get; set; }
public override bool Evaluate(object obj)
{
if (obj is bool boolObj)
{
return boolObj == Value;
/*switch (Op)
{
case Operator.Is:
return boolObj == Value;
}*/
}
return false;
}
}
public class StringConditionResolver : ConditionResolver
{
public enum Operator
{
/// <summary>
/// 出现过
/// </summary>
Contains,
/// <summary>
/// 没有出现过
/// </summary>
DoesNotContain,
/// <summary>
/// 相等
/// </summary>
Equal,
/// <summary>
/// 不相等
/// </summary>
NotEqual,
/// <summary>
/// 起始字符串等于
/// </summary>
StartsWith,
/// <summary>
/// 结束字符串等于
/// </summary>
EndsWith
}
public Operator Op { get; set; }
public string Value { get; set; }
public override bool Evaluate(object obj)
{
if (obj is string strObj)
{
return Op switch
{
Operator.Contains => strObj.Contains(Value),
Operator.DoesNotContain => !strObj.Contains(Value),
Operator.Equal => strObj == Value,
Operator.NotEqual => strObj != Value,
Operator.StartsWith => strObj.StartsWith(Value),
Operator.EndsWith => strObj.EndsWith(Value),
_ => throw new NotSupportedException("不支持的条件类型"),
};
/* switch (Op)
{
case Operator.Contains:
return strObj.Contains(Value);
case Operator.DoesNotContain:
return !strObj.Contains(Value);
case Operator.Equal:
return strObj == Value;
case Operator.NotEqual:
return strObj != Value;
case Operator.StartsWith:
return strObj.StartsWith(Value);
case Operator.EndsWith:
return strObj.EndsWith(Value);
}*/
}
return false;
}
}
public class MemberConditionResolver<T> : ConditionResolver where T : struct, IComparable<T>
{
//public string MemberPath { get; set; }
public ValueTypeConditionResolver<T>.Operator Op { get; set; }
public object? TargetObj { get; set; }
public T Value { get; set; }
public string ArithmeticExpression { get; set; }
public override bool Evaluate(object? obj)
{
//object? memberValue = GetMemberValue(obj, MemberPath);
if (TargetObj is T typedObj)
{
return new ValueTypeConditionResolver<T>
{
Op = Op,
Value = Value,
ArithmeticExpression = ArithmeticExpression,
}.Evaluate(typedObj);
}
return false;
}
//private object? GetMemberValue(object? obj, string memberPath)
//{
// string[] members = memberPath[1..].Split('.');
// foreach (var member in members)
// {
// if (obj == null) return null;
// Type type = obj.GetType();
// PropertyInfo? propertyInfo = type.GetProperty(member);
// FieldInfo? fieldInfo = type.GetField(member);
// if (propertyInfo != null)
// obj = propertyInfo.GetValue(obj);
// else if (fieldInfo != null)
// obj = fieldInfo.GetValue(obj);
// else
// throw new ArgumentException($"Member {member} not found in type {type.FullName}");
// }
// return obj;
//}
}
public class MemberStringConditionResolver : ConditionResolver
{
public string MemberPath { get; set; }
public StringConditionResolver.Operator Op { get; set; }
public string Value { get; set; }
public override bool Evaluate(object obj)
{
object memberValue = GetMemberValue(obj, MemberPath);
if (memberValue is string strObj)
{
return new StringConditionResolver
{
Op = Op,
Value = Value
}.Evaluate(strObj);
}
return false;
}
private object GetMemberValue(object? obj, string memberPath)
{
string[] members = memberPath[1..].Split('.');
foreach (var member in members)
{
if (obj == null) return null;
Type type = obj.GetType();
PropertyInfo? propertyInfo = type.GetProperty(member);
FieldInfo? fieldInfo = type.GetField(member);
if (propertyInfo != null)
obj = propertyInfo.GetValue(obj);
else if (fieldInfo != null)
obj = fieldInfo.GetValue(obj);
else
throw new ArgumentException($"Member {member} not found in type {type.FullName}");
}
return obj;
}
private static string GetArithmeticExpression(string part)
{
int startIndex = part.IndexOf('[');
int endIndex = part.IndexOf(']');
if (startIndex >= 0 && endIndex > startIndex)
{
return part.Substring(startIndex + 1, endIndex - startIndex - 1);
}
return null;
}
}
}

View File

@@ -0,0 +1,329 @@
using System;
using System.Globalization;
using System.Linq;
using System.Reflection;
namespace Serein.Flow.SerinExpression;
public class SerinConditionParser
{
public static bool To<T>(T data, string expression)
{
try
{
return ConditionParse(data, expression).Evaluate(data);
}
catch (Exception ex)
{
Console.WriteLine(ex);
throw;
}
}
public static ConditionResolver ConditionParse(object data, string expression)
{
if (expression.StartsWith('.') /*&& expression.Contains('<') && expression.Contains('>')*/)
{
return ParseObjectExpression(data, expression);
}
else
{
return ParseSimpleExpression(data, expression);
}
bool ContainsArithmeticOperators(string expression)
{
return expression.Contains('+') || expression.Contains('-') || expression.Contains('*') || expression.Contains('/');
}
}
private static string GetArithmeticExpression(string part)
{
int startIndex = part.IndexOf('[');
int endIndex = part.IndexOf(']');
if (startIndex >= 0 && endIndex > startIndex)
{
return part.Substring(startIndex + 1, endIndex - startIndex - 1);
}
return null;
}
private static object? GetMemberValue(object? obj, string memberPath)
{
string[] members = memberPath[1..].Split('.');
foreach (var member in members)
{
if (obj == null) return null;
Type type = obj.GetType();
PropertyInfo? propertyInfo = type.GetProperty(member);
FieldInfo? fieldInfo = type.GetField(member);
if (propertyInfo != null)
obj = propertyInfo.GetValue(obj);
else if (fieldInfo != null)
obj = fieldInfo.GetValue(obj);
else
throw new ArgumentException($"Member {member} not found in type {type.FullName}");
}
return obj;
}
private static ConditionResolver ParseObjectExpression(object data, string expression)
{
var parts = expression.Split(' ');
string operatorStr = parts[0];
string valueStr = string.Join(' ', parts, 1, parts.Length - 1);
int typeStartIndex = expression.IndexOf('<');
int typeEndIndex = expression.IndexOf('>');
string memberPath;
Type type;
object? targetObj;
if ((typeStartIndex + typeStartIndex) == -2)
{
memberPath = operatorStr;
targetObj = GetMemberValue(data, operatorStr);
type = targetObj.GetType();
operatorStr = parts[1].ToLower();
valueStr = string.Join(' ', parts.Skip(2));
}
else
{
if (typeStartIndex >= typeEndIndex)
{
throw new ArgumentException("无效的表达式格式");
}
memberPath = expression.Substring(0, typeStartIndex).Trim();
string typeStr = expression.Substring(typeStartIndex + 1, typeEndIndex - typeStartIndex - 1).Trim().ToLower();
parts = expression.Substring(typeEndIndex + 1).Trim().Split(' ');
if (parts.Length == 3)
{
operatorStr = parts[1].ToLower();
valueStr = string.Join(' ', parts.Skip(2));
}
else
{
operatorStr = parts[0].ToLower();
valueStr = string.Join(' ', parts.Skip(1));
}
targetObj = GetMemberValue(data, memberPath);
Type? tempType = typeStr switch
{
"int" => typeof(int),
"double" => typeof(double),
"bool" => typeof(bool),
"string" => typeof(string),
_ => Type.GetType(typeStr)
};
type = tempType ?? throw new ArgumentException("对象表达式无效的类型声明");
}
if (type == typeof(int))
{
int value = int.Parse(valueStr, CultureInfo.InvariantCulture);
return new MemberConditionResolver<int>
{
TargetObj = targetObj,
//MemberPath = memberPath,
Op = ParseValueTypeOperator<int>(operatorStr),
Value = value,
ArithmeticExpression = GetArithmeticExpression(parts[0])
};
}
else if (type == typeof(double))
{
double value = double.Parse(valueStr, CultureInfo.InvariantCulture);
return new MemberConditionResolver<double>
{
//MemberPath = memberPath,
TargetObj = targetObj,
Op = ParseValueTypeOperator<double>(operatorStr),
Value = value,
ArithmeticExpression = GetArithmeticExpression(parts[0])
};
}
else if (type == typeof(bool))
{
return new MemberConditionResolver<bool>
{
//MemberPath = memberPath,
TargetObj = targetObj,
Op = (ValueTypeConditionResolver<bool>.Operator)ParseBoolOperator(operatorStr)
};
}
else if (type == typeof(string))
{
return new MemberStringConditionResolver
{
MemberPath = memberPath,
Op = ParseStringOperator(operatorStr),
Value = valueStr
};
}
throw new NotSupportedException($"Type {type} is not supported.");
}
private static ConditionResolver ParseSimpleExpression(object data, string expression)
{
if ("pass".Equals(expression.ToLower()))
{
return new PassConditionResolver
{
Op = PassConditionResolver.Operator.Pass,
};
}
else
{
if ("not pass".Equals(expression.ToLower()))
{
return new PassConditionResolver
{
Op = PassConditionResolver.Operator.NotPass,
};
}
if ("!pass".Equals(expression.ToLower()))
{
return new PassConditionResolver
{
Op = PassConditionResolver.Operator.NotPass,
};
}
}
var parts = expression.Split(' ');
if (parts.Length < 2)
throw new ArgumentException("无效的表达式格式。");
//string typeStr = parts[0];
string operatorStr = parts[0];
string valueStr = string.Join(' ', parts, 1, parts.Length - 1);
Type type = data.GetType();//Type.GetType(typeStr);
if (type == typeof(int))
{
var op = ParseValueTypeOperator<int>(operatorStr);
if (op == ValueTypeConditionResolver<int>.Operator.InRange || op == ValueTypeConditionResolver<int>.Operator.OutOfRange)
{
var temp = valueStr.Split('-');
if (temp.Length < 2)
throw new ArgumentException($"范围无效:{valueStr}。");
int rangeStart = int.Parse(temp[0], CultureInfo.InvariantCulture);
int rangeEnd = int.Parse(temp[1], CultureInfo.InvariantCulture);
return new ValueTypeConditionResolver<int>
{
Op = op,
RangeStart = rangeStart,
RangeEnd = rangeEnd,
ArithmeticExpression = GetArithmeticExpression(parts[0]),
};
}
else
{
int value = int.Parse(valueStr, CultureInfo.InvariantCulture);
return new ValueTypeConditionResolver<int>
{
Op = op,
Value = value,
ArithmeticExpression = GetArithmeticExpression(parts[0])
};
}
}
else if (type == typeof(double))
{
double value = double.Parse(valueStr, CultureInfo.InvariantCulture);
return new ValueTypeConditionResolver<double>
{
Op = ParseValueTypeOperator<double>(operatorStr),
Value = value,
ArithmeticExpression = GetArithmeticExpression(parts[0])
};
}
else if (type == typeof(bool))
{
bool value = bool.Parse(valueStr);
return new BoolConditionResolver
{
Op = ParseBoolOperator(operatorStr),
Value = value,
};
}
else if (type == typeof(string))
{
return new StringConditionResolver
{
Op = ParseStringOperator(operatorStr),
Value = valueStr
};
}
throw new NotSupportedException($"Type {type} is not supported.");
}
private static ValueTypeConditionResolver<T>.Operator ParseValueTypeOperator<T>(string operatorStr) where T : struct, IComparable<T>
{
return operatorStr switch
{
">" => ValueTypeConditionResolver<T>.Operator.GreaterThan,
"<" => ValueTypeConditionResolver<T>.Operator.LessThan,
"==" => ValueTypeConditionResolver<T>.Operator.Equal,
">=" => ValueTypeConditionResolver<T>.Operator.GreaterThanOrEqual,
"≥" => ValueTypeConditionResolver<T>.Operator.GreaterThanOrEqual,
"<=" => ValueTypeConditionResolver<T>.Operator.LessThanOrEqual,
"≤" => ValueTypeConditionResolver<T>.Operator.LessThanOrEqual,
"equals" => ValueTypeConditionResolver<T>.Operator.Equal,
"in" => ValueTypeConditionResolver<T>.Operator.InRange,
"!in" => ValueTypeConditionResolver<T>.Operator.OutOfRange,
_ => throw new ArgumentException($"Invalid operator {operatorStr} for value type.")
};
}
private static BoolConditionResolver.Operator ParseBoolOperator(string operatorStr)
{
return operatorStr switch
{
"is" => BoolConditionResolver.Operator.Is,
"==" => BoolConditionResolver.Operator.Is,
"equals" => BoolConditionResolver.Operator.Is,
//"isFalse" => BoolConditionNode.Operator.IsFalse,
_ => throw new ArgumentException($"Invalid operator {operatorStr} for bool type.")
};
}
private static StringConditionResolver.Operator ParseStringOperator(string operatorStr)
{
return operatorStr switch
{
"c" => StringConditionResolver.Operator.Contains,
"nc" => StringConditionResolver.Operator.DoesNotContain,
"sw" => StringConditionResolver.Operator.StartsWith,
"ew" => StringConditionResolver.Operator.EndsWith,
"contains" => StringConditionResolver.Operator.Contains,
"doesNotContain" => StringConditionResolver.Operator.DoesNotContain,
"equals" => StringConditionResolver.Operator.Equal,
"==" => StringConditionResolver.Operator.Equal,
"notEquals" => StringConditionResolver.Operator.NotEqual,
"!=" => StringConditionResolver.Operator.NotEqual,
"startsWith" => StringConditionResolver.Operator.StartsWith,
"endsWith" => StringConditionResolver.Operator.EndsWith,
_ => throw new ArgumentException($"Invalid operator {operatorStr} for string type.")
};
}
}

View File

@@ -0,0 +1,214 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static Serein.Flow.NodeModel.SingleExpOpNode;
using static System.Runtime.InteropServices.JavaScript.JSType;
namespace Serein.Flow.SerinExpression
{
public class SerinArithmeticExpressionEvaluator
{
private static readonly DataTable table = new DataTable();
public static double Evaluate(string expression, double inputValue)
{
// 替换占位符@为输入值
expression = expression.Replace("@", inputValue.ToString());
try
{
// 使用 DataTable.Compute 方法计算表达式
var result = table.Compute(expression, string.Empty);
return Convert.ToDouble(result);
}
catch
{
throw new ArgumentException("Invalid arithmetic expression.");
}
}
}
public class SerinExpressionEvaluator
{
public static object Evaluate(string expression, object targetObJ,out bool IsChange)
{
var parts = expression.Split([' '], 2);
if (parts.Length != 2)
{
throw new ArgumentException("Invalid expression format.");
}
var operation = parts[0].ToLower();
var operand = parts[1][0] == '.' ? parts[1][1..]: parts[1];
var result = operation switch
{
"@num" => ComputedNumber(targetObJ, operand),
"@call" => InvokeMethod(targetObJ, operand),
"@get" => GetMember(targetObJ, operand),
"@set" => SetMember(targetObJ, operand),
_ => throw new NotSupportedException($"Operation {operation} is not supported.")
};
IsChange = operation switch
{
"@num" => true,
"@call" => true,
"@get" => true,
"@set" => false,
_ => throw new NotSupportedException($"Operation {operation} is not supported.")
};
return result;
}
private static readonly char[] separator = ['(', ')'];
private static readonly char[] separatorArray = [','];
private static object InvokeMethod(object target, string methodCall)
{
var methodParts = methodCall.Split(separator, StringSplitOptions.RemoveEmptyEntries);
if (methodParts.Length != 2)
{
throw new ArgumentException("Invalid method call format.");
}
var methodName = methodParts[0];
var parameterList = methodParts[1];
var parameters = parameterList.Split(separatorArray, StringSplitOptions.RemoveEmptyEntries)
.Select(p => p.Trim())
.ToArray();
var method = target.GetType().GetMethod(methodName);
if (method == null)
{
throw new ArgumentException($"Method {methodName} not found on target.");
}
var parameterValues = method.GetParameters()
.Select((p, index) => Convert.ChangeType(parameters[index], p.ParameterType))
.ToArray();
return method.Invoke(target, parameterValues);
}
private static object GetMember(object target, string memberPath)
{
var members = memberPath.Split('.');
foreach (var member in members)
{
if (target == null) return null;
var property = target.GetType().GetProperty(member);
if (property != null)
{
target = property.GetValue(target);
}
else
{
var field = target.GetType().GetField(member);
if (field != null)
{
target = field.GetValue(target);
}
else
{
throw new ArgumentException($"Member {member} not found on target.");
}
}
}
return target;
}
private static object SetMember(object target, string assignment)
{
var parts = assignment.Split(new[] { '=' }, 2);
if (parts.Length != 2)
{
throw new ArgumentException("Invalid assignment format.");
}
var memberPath = parts[0].Trim();
var value = parts[1].Trim();
var members = memberPath.Split('.');
for (int i = 0; i < members.Length - 1; i++)
{
var member = members[i];
var property = target.GetType().GetProperty(member);
if (property != null)
{
target = property.GetValue(target);
}
else
{
var field = target.GetType().GetField(member);
if (field != null)
{
target = field.GetValue(target);
}
else
{
throw new ArgumentException($"Member {member} not found on target.");
}
}
}
var lastMember = members.Last();
var lastProperty = target.GetType().GetProperty(lastMember);
if (lastProperty != null)
{
var convertedValue = Convert.ChangeType(value, lastProperty.PropertyType);
lastProperty.SetValue(target, convertedValue);
}
else
{
var lastField = target.GetType().GetField(lastMember);
if (lastField != null)
{
var convertedValue = Convert.ChangeType(value, lastField.FieldType);
lastField.SetValue(target, convertedValue);
}
else
{
throw new ArgumentException($"Member {lastMember} not found on target.");
}
}
return target;
}
private static double ComputedNumber(object value,string expression)
{
double numericValue = Convert.ToDouble(value);
if (!string.IsNullOrEmpty(expression))
{
numericValue = SerinArithmeticExpressionEvaluator.Evaluate(expression, numericValue);
}
return numericValue;
}
}
}

View File

@@ -0,0 +1,192 @@
using Serein.Library.IOC;
using System.Collections.Concurrent;
using System.Reflection;
namespace Serein.Flow.Tool;
public static class DelegateCache
{
/// <summary>
/// 委托缓存全局字典
/// </summary>
public static ConcurrentDictionary<string, Delegate> GlobalDicDelegates { get; } = new ConcurrentDictionary<string, Delegate>();
}
public static class DelegateGenerator
{
// 缓存的实例对象(键:类型名称)
public static ConcurrentDictionary<string, object> DynamicInstanceToType { get; } = new ConcurrentDictionary<string, object>();
// 缓存的实例对象 (键:生成的方法名称)
// public static ConcurrentDictionary<string, object> DynamicInstance { get; } = new ConcurrentDictionary<string, object>();
/// <summary>
/// 生成方法信息
/// </summary>
/// <param name="serviceContainer"></param>
/// <param name="type"></param>
/// <returns></returns>
public static ConcurrentDictionary<string, MethodDetails> GenerateMethodDetails(IServiceContainer serviceContainer, Type type)
{
var methodDetailsDictionary = new ConcurrentDictionary<string, MethodDetails>();
var assemblyName = type.Assembly.GetName().Name;
var methods = GetMethodsToProcess(type);
foreach (var method in methods)
{
var methodDetails = CreateMethodDetails(serviceContainer, type, method, assemblyName);
methodDetailsDictionary.TryAdd(methodDetails.MethodName, methodDetails);
}
return methodDetailsDictionary;
}
/// <summary>
/// 获取处理方法
/// </summary>
private static IEnumerable<MethodInfo> GetMethodsToProcess(Type type)
{
return type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
.Where(m => m.GetCustomAttribute<MethodDetailAttribute>()?.Scan == true);
}
/// <summary>
/// 创建方法信息
/// </summary>
/// <returns></returns>
private static MethodDetails CreateMethodDetails(IServiceContainer serviceContainer, Type type, MethodInfo method, string assemblyName)
{
var methodName = method.Name;
var attribute = method.GetCustomAttribute<MethodDetailAttribute>();
var explicitDataOfParameters = GetExplicitDataOfParameters(method.GetParameters());
// 生成委托
var methodDelegate = GenerateMethodDelegate(type, // 方法所在的对象类型
method, // 方法信息
method.GetParameters(),// 方法参数
method.ReturnType);// 返回值
var dllTypeName = $"{assemblyName}.{type.Name}";
serviceContainer.Register(type);
object instance = serviceContainer.GetOrCreateServiceInstance(type);
var dllTypeMethodName = $"{assemblyName}.{type.Name}.{method.Name}";
return new MethodDetails
{
ActingInstanceType = type,
ActingInstance = instance,
MethodName = dllTypeMethodName,
MethodDelegate = methodDelegate,
MethodDynamicType = attribute.MethodDynamicType,
MethodLockName = attribute.LockName,
MethodTips = attribute.MethodTips,
ExplicitDatas = explicitDataOfParameters,
ReturnType = method.ReturnType,
};
}
private static ExplicitData[] GetExplicitDataOfParameters(ParameterInfo[] parameters)
{
return parameters.Select((it, index) =>
{
//Console.WriteLine($"{it.Name}-{it.HasDefaultValue}-{it.DefaultValue}");
string explicitTypeName = GetExplicitTypeName(it.ParameterType);
var items = GetExplicitItems(it.ParameterType, explicitTypeName);
if ("Bool".Equals(explicitTypeName)) explicitTypeName = "Select"; // 布尔值 转为 可选类型
return new ExplicitData
{
IsExplicitData = it.GetCustomAttribute(typeof(ExplicitAttribute)) is ExplicitAttribute,
Index = index,
ExplicitType = it.ParameterType,
ExplicitTypeName = explicitTypeName,
DataType = it.ParameterType,
ParameterName = it.Name,
DataValue = it.HasDefaultValue ? it.DefaultValue.ToString() : "",
Items = items.ToArray(),
};
}).ToArray();
}
private static string GetExplicitTypeName(Type type)
{
return type switch
{
Type t when t.IsEnum => "Select",
Type t when t == typeof(bool) => "Bool",
Type t when t == typeof(string) => "Value",
Type t when t == typeof(int) => "Value",
Type t when t == typeof(double) => "Value",
_ => "Value"
};
}
private static IEnumerable<string> GetExplicitItems(Type type, string explicitTypeName)
{
return explicitTypeName switch
{
"Select" => Enum.GetNames(type),
"Bool" => ["True", "False"],
_ => []
};
}
private static Delegate GenerateMethodDelegate(Type type, MethodInfo methodInfo, ParameterInfo[] parameters, Type returnType)
{
var parameterTypes = parameters.Select(p => p.ParameterType).ToArray();
var parameterCount = parameters.Length;
if (returnType == typeof(void))
{
if (parameterCount == 0)
{
// 无返回值,无参数
return ExpressionHelper.MethodCaller(type, methodInfo);
}
else
{
// 无返回值,有参数
return ExpressionHelper.MethodCaller(type, methodInfo, parameterTypes);
}
}
else if (returnType == typeof(Task<FlipflopContext>)) // 触发器
{
if (parameterCount == 0)
{
// 有返回值,无参数
return ExpressionHelper.MethodCallerAsync(type, methodInfo);
}
else
{
// 有返回值,有参数
return ExpressionHelper.MethodCallerAsync(type, methodInfo, parameterTypes);
}
}
else
{
if (parameterCount == 0)
{
// 有返回值,无参数
return ExpressionHelper.MethodCallerHaveResult(type, methodInfo);
}
else
{
// 有返回值,有参数
return ExpressionHelper.MethodCallerHaveResult(type, methodInfo, parameterTypes);
}
}
}
}

View File

@@ -0,0 +1,194 @@
namespace Serein.Flow.Tool
{
#region tsk工具 (
/*public class LockManager
{
private readonly ConcurrentDictionary<string, LockQueue> _locks = new ConcurrentDictionary<string, LockQueue>();
public void CreateLock(string name)
{
_locks.TryAdd(name, new LockQueue());
}
public async Task AcquireLockAsync(string name, CancellationToken cancellationToken = default)
{
if (!_locks.ContainsKey(name))
{
throw new ArgumentException($"Lock with name '{name}' does not exist.");
}
var lockQueue = _locks[name];
var tcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
lock (lockQueue.Queue)
{
lockQueue.Queue.Enqueue(tcs);
if (lockQueue.Queue.Count == 1)
{
tcs.SetResult(true);
}
}
await tcs.Task.ConfigureAwait(false);
// 处理取消操作
if (cancellationToken.CanBeCanceled)
{
cancellationToken.Register(() =>
{
lock (lockQueue.Queue)
{
if (lockQueue.Queue.Contains(tcs))
{
tcs.TrySetCanceled();
}
}
});
}
}
public void ReleaseLock(string name)
{
if (!_locks.ContainsKey(name))
{
throw new ArgumentException($"Lock with name '{name}' does not exist.");
}
var lockQueue = _locks[name];
lock (lockQueue.Queue)
{
if (lockQueue.Queue.Count > 0)
{
lockQueue.Queue.Dequeue();
if (lockQueue.Queue.Count > 0)
{
var next = lockQueue.Queue.Peek();
next.SetResult(true);
}
}
}
}
private class LockQueue
{
public Queue<TaskCompletionSource<bool>> Queue { get; } = new Queue<TaskCompletionSource<bool>>();
}
}
public interface ITaskResult
{
object Result { get; }
}
public class TaskResult<T> : ITaskResult
{
public TaskResult(T result)
{
Result = result;
}
public T Result { get; }
object ITaskResult.Result => Result;
}
public class DynamicTasks
{
private static readonly ConcurrentDictionary<string, Task<ITaskResult>> TaskGuidPairs = new();
public static Task<ITaskResult> GetTask(string Guid)
{
TaskGuidPairs.TryGetValue(Guid, out Task<ITaskResult> task);
return task;
}
public static bool AddTask<T>(string Guid, T result)
{
var task = Task.FromResult<ITaskResult>(new TaskResult<T>(result));
return TaskGuidPairs.TryAdd(Guid, task);
}
}
public class TaskNodeManager
{
private readonly ConcurrentDictionary<string, TaskQueue> _taskQueues = new ConcurrentDictionary<string, TaskQueue>();
public void CreateTaskNode(string name)
{
_taskQueues.TryAdd(name, new TaskQueue());
}
public async Task WaitForTaskNodeAsync(string name, CancellationToken cancellationToken = default)
{
if (!_taskQueues.ContainsKey(name))
{
throw new ArgumentException($"Task node with name '{name}' does not exist.");
}
var taskQueue = _taskQueues[name];
var tcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
lock (taskQueue.Queue)
{
taskQueue.Queue.Enqueue(tcs);
if (taskQueue.Queue.Count == 1)
{
tcs.SetResult(true);
}
}
await tcs.Task.ConfigureAwait(false);
// 处理取消操作
if (cancellationToken.CanBeCanceled)
{
cancellationToken.Register(() =>
{
lock (taskQueue.Queue)
{
if (taskQueue.Queue.Contains(tcs))
{
tcs.TrySetCanceled();
}
}
});
}
}
public void CompleteTaskNode(string name)
{
if (!_taskQueues.ContainsKey(name))
{
throw new ArgumentException($"Task node with name '{name}' does not exist.");
}
var taskQueue = _taskQueues[name];
lock (taskQueue.Queue)
{
if (taskQueue.Queue.Count > 0)
{
taskQueue.Queue.Dequeue();
if (taskQueue.Queue.Count > 0)
{
var next = taskQueue.Queue.Peek();
next.SetResult(true);
}
}
}
}
private class TaskQueue
{
public Queue<TaskCompletionSource<bool>> Queue { get; } = new Queue<TaskCompletionSource<bool>>();
}
}*/
#endregion
}

View File

@@ -0,0 +1,740 @@
using System.Collections.Concurrent;
using System.Linq.Expressions;
using System.Reflection;
namespace Serein.Flow.Tool
{
/// <summary>
/// 对于实例创建的表达式树反射
/// </summary>
public static class ExpressionHelper
{
/// <summary>
/// 缓存表达式树反射方法
/// </summary>
private static ConcurrentDictionary<string, Delegate> Cache { get; } = new ConcurrentDictionary<string, Delegate>();
public static List<string> GetCacheKey()
{
return [.. Cache.Keys];
}
#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);
var lambda = Expression.Lambda(Expression.Convert(methodCall, typeof(object)), parameter);
// Func<object, object>
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,
(Expression[])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
);
// 创建 lambda 表达式
var lambda = Expression.Lambda<Func<object, object[], object>>(
Expression.Convert(methodCall, typeof(object)),
instanceParam,
argsParam
);
//var resule = task.DynamicInvoke((object)[Activator.CreateInstance(type), [new DynamicContext(null)]]);
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,
(Expression[])convertedArgs
);
// 创建 lambda 表达式
var lambda = Expression.Lambda<Func<object, object[], Task<FlipflopContext>>>(
Expression.Convert(methodCall, typeof(Task<FlipflopContext>)),
instanceParam,
argsParam
);
//var resule = task.DynamicInvoke((object)[Activator.CreateInstance(type), [new DynamicContext(null)]]);
return lambda.Compile();
}
#region
/// <summary>
/// 表达式树构建单参数,无返回值的方法
/// </summary>
public static Delegate MethodCaller(Type type, string methodName, Type parameterType)
{
string cacheKey = $"{type.FullName}.{methodName}.MethodCallerWithParam";
return Cache.GetOrAdd(cacheKey, _ => CreateMethodCallerDelegate(type, methodName, parameterType));
}
/// <summary>
/// 表达式树构建单参数,无返回值的方法
/// </summary>
private static Delegate CreateMethodCallerDelegate(Type type, string methodName, Type parameterType)
{
var parameter = Expression.Parameter(typeof(object), "instance");
var argument = Expression.Parameter(typeof(object), "argument");
var methodCall = Expression.Call(Expression.Convert(parameter, type),
type.GetMethod(methodName, [parameterType])!,
Expression.Convert(argument, parameterType));
var lambda = Expression.Lambda(methodCall, parameter, argument);
return lambda.Compile();
}
/// <summary>
/// 表达式树构建单参数,有返回值的方法
/// </summary>
public static Delegate MethodCallerWithResult(Type type, string methodName, Type parameterType, Type returnType)
{
string cacheKey = $"{type.FullName}.{methodName}.MethodCallerWithResult";
return Cache.GetOrAdd(cacheKey, _ => CreateMethodCallerDelegateWithResult(type, methodName, parameterType, returnType));
}
/// <summary>
/// 表达式树构建单参数,有返回值的方法
/// </summary>
private static Delegate CreateMethodCallerDelegateWithResult(Type type, string methodName, Type parameterType, Type returnType)
{
var parameter = Expression.Parameter(typeof(object), "instance");
var argument = Expression.Parameter(typeof(object), "argument");
var methodCall = Expression.Call(Expression.Convert(parameter, type),
type.GetMethod(methodName, [parameterType])!,
Expression.Convert(argument, parameterType));
var lambda = Expression.Lambda(Expression.Convert(methodCall, typeof(object)), parameter, argument);
return lambda.Compile();
}
#endregion
#endregion
#region
/*
/// <summary>
/// 动态获取属性值
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TProperty"></typeparam>
/// <param name="propertyName"></param>
/// <returns></returns>
public static Func<T, TProperty> PropertyGetter<T, TProperty>(string propertyName)
{
string cacheKey = $"{typeof(T).FullName}.{propertyName}.Getter";
return (Func<T, TProperty>)Cache.GetOrAdd(cacheKey, _ => CreateGetterDelegate<T, TProperty>(propertyName));
}
private static Func<T, TProperty> CreateGetterDelegate<T, TProperty>(string propertyName)
{
var parameter = Expression.Parameter(typeof(T), "instance");
var property = Expression.Property(parameter, propertyName);
var lambda = Expression.Lambda<Func<T, TProperty>>(property, parameter);
return lambda.Compile();
}
/// <summary>
/// 动态设置属性值
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TProperty"></typeparam>
/// <param name="propertyName"></param>
/// <returns></returns>
public static Action<T, TProperty> PropertySetter<T, TProperty>(string propertyName)
{
string cacheKey = $"{typeof(T).FullName}.{propertyName}.Setter";
return (Action<T, TProperty>)Cache.GetOrAdd(cacheKey, _ => CreateSetterDelegate<T, TProperty>(propertyName));
}
private static Action<T, TProperty> CreateSetterDelegate<T, TProperty>(string propertyName)
{
var parameter = Expression.Parameter(typeof(T), "instance");
var value = Expression.Parameter(typeof(TProperty), "value");
var property = Expression.Property(parameter, propertyName);
var assign = Expression.Assign(property, value);
var lambda = Expression.Lambda<Action<T, TProperty>>(assign, parameter, value);
return lambda.Compile();
}
/// <summary>
/// 动态获取字段值
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TField"></typeparam>
/// <param name="fieldName"></param>
/// <returns></returns>
public static Func<T, TField> FieldGetter<T, TField>(string fieldName)
{
string cacheKey = $"{typeof(T).FullName}.{fieldName}.FieldGetter";
return (Func<T, TField>)Cache.GetOrAdd(cacheKey, _ => CreateFieldGetterDelegate<T, TField>(fieldName));
}
private static Func<T, TField> CreateFieldGetterDelegate<T, TField>(string fieldName)
{
var parameter = Expression.Parameter(typeof(T), "instance");
var field = Expression.Field(parameter, fieldName);
var lambda = Expression.Lambda<Func<T, TField>>(field, parameter);
return lambda.Compile();
}
/// <summary>
/// 动态设置字段值
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TField"></typeparam>
/// <param name="fieldName"></param>
/// <returns></returns>
public static Action<T, TField> FieldSetter<T, TField>(string fieldName)
{
string cacheKey = $"{typeof(T).FullName}.{fieldName}.FieldSetter";
return (Action<T, TField>)Cache.GetOrAdd(cacheKey, _ => CreateFieldSetterDelegate<T, TField>(fieldName));
}
private static Action<T, TField> CreateFieldSetterDelegate<T, TField>(string fieldName)
{
var parameter = Expression.Parameter(typeof(T), "instance");
var value = Expression.Parameter(typeof(TField), "value");
var field = Expression.Field(parameter, fieldName);
var assign = Expression.Assign(field, value);
var lambda = Expression.Lambda<Action<T, TField>>(assign, parameter, value);
return lambda.Compile();
}
/// <summary>
/// 动态调用无参数方法
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="methodName"></param>
/// <returns></returns>
public static Action<T> MethodCaller<T>(string methodName)
{
string cacheKey = $"{typeof(T).FullName}.{methodName}.MethodCaller";
return (Action<T>)Cache.GetOrAdd(cacheKey, _ => CreateMethodCallerDelegate<T>(methodName));
}
private static Action<T> CreateMethodCallerDelegate<T>(string methodName)
{
var parameter = Expression.Parameter(typeof(T), "instance");
var methodCall = Expression.Call(parameter, typeof(T).GetMethod(methodName));
var lambda = Expression.Lambda<Action<T>>(methodCall, parameter);
return lambda.Compile();
}
/// <summary>
/// 动态调用无参有返回值方法
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TResult"></typeparam>
/// <param name="methodName"></param>
/// <returns></returns>
public static Func<T, TResult> MethodCallerHaveResul<T, TResult>(string methodName)
{
string cacheKey = $"{typeof(T).FullName}.{methodName}.MethodCaller";
return (Func<T, TResult>)Cache.GetOrAdd(cacheKey, _ => CreateMethodCallerDelegateHaveResult<T, TResult>(methodName));
}
private static Func<T, TResult> CreateMethodCallerDelegateHaveResult<T, TResult>(string methodName)
{
var parameter = Expression.Parameter(typeof(T), "instance");
var methodCall = Expression.Call(parameter, typeof(T).GetMethod(methodName));
var lambda = Expression.Lambda<Func<T, TResult>>(methodCall, parameter);
return lambda.Compile();
}
/// <summary>
/// 动态调用单参数无返回值的方法
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TParam"></typeparam>
/// <param name="methodName"></param>
/// <returns></returns>
public static Action<T, TParam> MethodCaller<T, TParam>(string methodName)
{
string cacheKey = $"{typeof(T).FullName}.{methodName}.MethodCallerWithParam";
return (Action<T, TParam>)Cache.GetOrAdd(cacheKey, _ => CreateMethodCallerDelegate<T, TParam>(methodName));
}
private static Action<T, TParam> CreateMethodCallerDelegate<T, TParam>(string methodName)
{
var parameter = Expression.Parameter(typeof(T), "instance");
var argument = Expression.Parameter(typeof(TParam), "argument");
var methodCall = Expression.Call(parameter, typeof(T).GetMethod(methodName), argument);
var lambda = Expression.Lambda<Action<T, TParam>>(methodCall, parameter, argument);
return lambda.Compile();
}
/// <summary>
/// 动态调用单参数有返回值的方法
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TParam"></typeparam>
/// <typeparam name="TResult"></typeparam>
/// <param name="methodName"></param>
/// <returns></returns>
public static Func<T, TParam, TResult> MethodCallerWithResult<T, TParam, TResult>(string methodName)
{
string cacheKey = $"{typeof(T).FullName}.{methodName}.MethodCallerWithResult";
return (Func<T, TParam, TResult>)Cache.GetOrAdd(cacheKey, _ => CreateMethodCallerDelegate<T, TParam, TResult>(methodName));
}
private static Func<T, TParam, TResult> CreateMethodCallerDelegate<T, TParam, TResult>(string methodName)
{
var parameter = Expression.Parameter(typeof(T), "instance");
var argument = Expression.Parameter(typeof(TParam), "argument");
var methodCall = Expression.Call(parameter, typeof(T).GetMethod(methodName), argument);
var lambda = Expression.Lambda<Func<T, TParam, TResult>>(methodCall, parameter, argument);
return lambda.Compile();
}
/// <summary>
/// 动态调用多参无返回值的方法
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="methodName"></param>
/// <param name="parameterTypes"></param>
/// <returns></returns>
public static Action<T, object[]> MethodCaller<T>(string methodName, params Type[] parameterTypes)
{
string cacheKey = $"{typeof(T).FullName}.{methodName}.MethodCaller";
return (Action<T, object[]>)Cache.GetOrAdd(cacheKey, _ => CreateMethodCallerDelegate<T>(methodName, parameterTypes));
}
private static Action<T, object[]> CreateMethodCallerDelegate<T>(string methodName, Type[] parameterTypes)
{
var parameter = Expression.Parameter(typeof(T), "instance");
var arguments = parameterTypes.Select((type, index) =>
Expression.Parameter(typeof(object), $"arg{index}")
).ToList();
var convertedArguments = arguments.Select((arg, index) =>
Expression.Convert(arg, parameterTypes[index])
).ToList();
var methodInfo = typeof(T).GetMethod(methodName, parameterTypes);
if (methodInfo == null)
{
throw new ArgumentException($"Method '{methodName}' not found in type '{typeof(T).FullName}' with given parameter types.");
}
var methodCall = Expression.Call(parameter, methodInfo, convertedArguments);
var lambda = Expression.Lambda<Action<T, object[]>>(methodCall, new[] { parameter }.Concat(arguments));
return lambda.Compile();
}
/// <summary>
/// 动态调用多参有返回值的方法
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TResult"></typeparam>
/// <param name="methodName"></param>
/// <param name="parameterTypes"></param>
/// <returns></returns>
public static Func<T, object[], TResult> MethodCallerHaveResult<T, TResult>(string methodName, Type[] parameterTypes)
{
string cacheKey = $"{typeof(T).FullName}.{methodName}.MethodCallerHaveResult";
return (Func<T, object[], TResult>)Cache.GetOrAdd(cacheKey, _ => CreateMethodCallerDelegate<T, TResult>(methodName, parameterTypes));
}
private static Func<T, object[], TResult> CreateMethodCallerDelegate<T, TResult>(string methodName, Type[] parameterTypes)
{
var instanceParam = Expression.Parameter(typeof(T), "instance");
var argsParam = Expression.Parameter(typeof(object[]), "args");
var convertedArgs = new Expression[parameterTypes.Length];
for (int i = 0; i < parameterTypes.Length; i++)
{
var index = Expression.Constant(i);
var argType = parameterTypes[i];
var arrayIndex = Expression.ArrayIndex(argsParam, index);
var convertedArg = Expression.Convert(arrayIndex, argType);
convertedArgs[i] = convertedArg;
}
var methodInfo = typeof(T).GetMethod(methodName, parameterTypes);
if (methodInfo == null)
{
throw new ArgumentException($"Method '{methodName}' not found in type '{typeof(T).FullName}' with given parameter types.");
}
var methodCall = Expression.Call(instanceParam, methodInfo, convertedArgs);
var lambda = Expression.Lambda<Func<T, object[], TResult>>(methodCall, instanceParam, argsParam);
return lambda.Compile();
}
*/
#endregion
#region
/* /// <summary>
/// 表达式树构建多个参数,有返回值的方法
/// </summary>
public static Delegate MethodCallerHaveResult(Type type, string methodName, Type[] parameterTypes)
{
string cacheKey = $"{type.FullName}.{methodName}.MethodCallerHaveResult";
return Cache.GetOrAdd(cacheKey, _ => CreateMethodCallerDelegateHaveResult(type, methodName, parameterTypes));
}
private static Delegate CreateMethodCallerDelegateHaveResult(Type type, string methodName, 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), type.GetMethod(methodName, parameterTypes), convertedArgs);
var lambda = Expression.Lambda(Expression.Convert(methodCall, typeof(object)), instanceParam, argsParam);
return lambda.Compile();
}*/
/*/// <summary>
/// 表达式反射 构建 无返回值、无参数 的委托
/// </summary>
/// <param name="type"></param>
/// <param name="methodName"></param>
/// <param name="parameterTypes"></param>
/// <returns></returns>
public static Delegate MethodCaller(Type type, string methodName, Type[] parameterTypes)
{
string cacheKey = $"{type.FullName}.{methodName}.{string.Join(",", parameterTypes.Select(t => t.FullName))}.MethodCaller";
return Cache.GetOrAdd(cacheKey, _ => CreateMethodCallerDelegate(type, methodName, parameterTypes));
}
/// <summary>
/// 表达式反射 构建 无返回值、无参数 的委托
/// </summary>
/// <param name="type"></param>
/// <param name="methodName"></param>
/// <param name="parameterTypes"></param>
/// <returns></returns>
private static Delegate CreateMethodCallerDelegate(Type type, string methodName, Type[] parameterTypes)
{
var parameter = Expression.Parameter(typeof(object), "instance");
var arguments = parameterTypes.Select((paramType, index) => Expression.Parameter(paramType, $"param{index}")).ToArray();
var methodCall = Expression.Call(Expression.Convert(parameter, type), type.GetMethod(methodName, parameterTypes), arguments);
var delegateType = Expression.GetActionType(new[] { typeof(object) }.Concat(parameterTypes).ToArray());
var lambda = Expression.Lambda(delegateType, methodCall, new[] { parameter }.Concat(arguments).ToArray());
return lambda.Compile();
}
*/
/*public static Delegate MethodCallerHaveResult(Type type, string methodName, Type returnType, Type[] parameterTypes)
{
string cacheKey = $"{type.FullName}.{methodName}.{string.Join(",", parameterTypes.Select(t => t.FullName))}.MethodCallerHaveResult";
return Cache.GetOrAdd(cacheKey, _ => CreateMethodCallerDelegateHaveResult(type, methodName, returnType, parameterTypes));
}
private static Delegate CreateMethodCallerDelegateHaveResult(Type type, string methodName, Type returnType, Type[] parameterTypes)
{
var parameter = Expression.Parameter(typeof(object), "instance");
var arguments = parameterTypes.Select((paramType, index) => Expression.Parameter(paramType, $"param{index}")).ToArray();
var methodCall = Expression.Call(Expression.Convert(parameter, type), type.GetMethod(methodName, parameterTypes), arguments);
var delegateType = Expression.GetFuncType(new[] { typeof(object) }.Concat(parameterTypes).Concat(new[] { typeof(object) }).ToArray());
var lambda = Expression.Lambda(delegateType, Expression.Convert(methodCall, typeof(object)), new[] { parameter }.Concat(arguments).ToArray());
return lambda.Compile();
}
*/
#endregion
}
}

View File

@@ -0,0 +1,80 @@
using System.Collections.Concurrent;
namespace Serein.Flow.Tool
{
public class TcsSignalException : Exception
{
public FfState FfState { get; set; }
public TcsSignalException(string? message) : base(message)
{
FfState = FfState.Cancel;
}
}
public class TcsSignal<TSignal> where TSignal : struct, Enum
{
public ConcurrentDictionary<TSignal, Stack<TaskCompletionSource<object>>> TcsEvent { get; } = new();
// public object tcsObj = new object();
public bool TriggerSignal<T>(TSignal signal, T state)
{
if (TcsEvent.TryRemove(signal, out var waitTcss))
{
while (waitTcss.Count > 0)
{
waitTcss.Pop().SetResult(state);
}
return true;
}
return false;
}
public TaskCompletionSource<object> CreateTcs(TSignal signal)
{
var tcs = new TaskCompletionSource<object>();
TcsEvent.GetOrAdd(signal, _ => new Stack<TaskCompletionSource<object>>()).Push(tcs);
return tcs;
}
//public TaskCompletionSource<object> GetOrCreateTcs(TSignal signal)
//{
// lock (tcsObj)
// {
// var tcs = TcsEvent.GetOrAdd(signal, _ => new TaskCompletionSource<object>());
// if (tcs.Task.IsCompleted)
// {
// TcsEvent.TryRemove(signal, out _);
// tcs = new TaskCompletionSource<object>();
// TcsEvent[signal] = tcs;
// }
// return tcs;
// }
//}
public void CancelTask()
{
lock(TcsEvent)
{
foreach (var tcss in TcsEvent.Values)
{
while (tcss.Count > 0)
{
tcss.Pop().SetException(new TcsSignalException("Task Cancel"));
}
}
TcsEvent.Clear();
}
}
}
}

View File

@@ -0,0 +1,116 @@
using System;
namespace Serein.Library.Core.Http
{
/// <summary>
/// 表示参数为url中的数据Get请求中不需要显式标注
/// </summary>
[AttributeUsage(AttributeTargets.Parameter)]
public sealed class IsUrlDataAttribute : Attribute
{
}
/// <summary>
/// 表示入参参数为整个boby的数据
/// <para>
/// 例如User类型含有int id、string name字段</para>
/// <para>
/// ① Add(User user)</para>
/// <para>请求需要传入的json为
/// {"user":{
/// "id":2,
/// "name":"李志忠"}}</para>
/// <para>
/// ② Add([Boby]User user)</para>
/// <para>请求需要传入的json为
/// {"id":2,"name":"李志忠"}</para>
///
/// </summary>
[AttributeUsage(AttributeTargets.Parameter)]
public sealed class IsBobyDataAttribute : Attribute
{
}
/// <summary>
/// 表示该控制器会被自动注册与程序集同一命名空间暂时不支持运行时自动加载DLL需要手动注册
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public sealed class AutoHostingAttribute(string url = "") : Attribute
{
public string Url { get; } = url;
}
/// <summary>
/// 表示该属性为自动注入依赖项
/// </summary>
[AttributeUsage(AttributeTargets.Property)]
public sealed class AutoInjectionAttribute : Attribute
{
}
/// <summary>
/// 方法的接口类型与附加URL
/// </summary>
/// <remarks>
/// 假设UserController.Add()的WebAPI特性中
/// http是HTTP.POST
/// url被显示标明“temp”
/// 那么请求的接口是POST,URL是
/// [http://localhost:8080]/user/add/temp
/// </remarks>
/// <param name="http"></param>
/// <param name="url"></param>
[AttributeUsage(AttributeTargets.Method)]
public sealed class WebApiAttribute() : Attribute
{
public API Type ;
public string Url ;
/// <summary>
/// 方法名称不作为url的部分
/// </summary>
public bool IsUrl;
}
[AttributeUsage(AttributeTargets.Method)]
public sealed class ApiPostAttribute() : Attribute
{
public string Url;
/// <summary>
/// 方法名称不作为url的部分
/// </summary>
public bool IsUrl = true;
}
[AttributeUsage(AttributeTargets.Method)]
public sealed class ApiGetAttribute() : Attribute
{
public string Url;
/// <summary>
/// 方法名称不作为url的部分
/// </summary>
public bool IsUrl = true;
}
/*public sealed class WebApiAttribute(API http, bool isUrl = true, string url = "") : Attribute
{
public API Http { get; } = http;
public string Url { get; } = url;
/// <summary>
/// 方法名称不作为url的部分
/// </summary>
public bool IsUrl { get; } = isUrl;
}*/
public enum API
{
POST,
GET,
//PUT,
//DELETE
}
}

View File

@@ -0,0 +1,17 @@
namespace Serein.Library.Core.Http
{
public class ControllerBase
{
public string Url { get; set; }
public string BobyData { get; set; }
public string GetLog(Exception ex)
{
return "Url : " + Url + Environment.NewLine +
"Ex : " + ex.Message + Environment.NewLine +
"Data : " + BobyData + Environment.NewLine;
}
}
}

753
Library.Core/Http/Router.cs Normal file
View File

@@ -0,0 +1,753 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Serein.Library.Api.Api;
using Serein.Library.Core.IOC;
using Serein.Tool;
using System.Collections;
using System.Collections.Concurrent;
using System.Net;
using System.Reflection;
using System.Text;
using System.Web;
using Enum = System.Enum;
using Type = System.Type;
namespace Serein.Library.Core.Http
{
/// <summary>
/// 路由注册与解析
/// </summary>
public class Router
{
private readonly ConcurrentDictionary<string, bool> _controllerAutoHosting; // 存储是否实例化
private readonly ConcurrentDictionary<string, Type> _controllerTypes; // 存储控制器类型
private readonly ConcurrentDictionary<string, object> _controllerInstances; // 存储控制器实例对象
private readonly ConcurrentDictionary<string, ConcurrentDictionary<string, MethodInfo>> _routes; // 用于存储路由信息
private readonly ISereinIoc serviceRegistry; // 用于存储路由信息
//private Type PostRequest;
public Router(ISereinIoc serviceRegistry) // 构造函数,初始化 Router 类的新实例
{
this.serviceRegistry = serviceRegistry;
_routes = new ConcurrentDictionary<string, ConcurrentDictionary<string, MethodInfo>>(); // 初始化路由字典
_controllerAutoHosting = new ConcurrentDictionary<string, bool>(); // 初始化控制器实例对象字典
_controllerTypes = new ConcurrentDictionary<string, Type>(); // 初始化控制器实例对象字典
_controllerInstances = new ConcurrentDictionary<string, object>(); // 初始化控制器实例对象字典
foreach (API method in Enum.GetValues(typeof(API))) // 遍历 HTTP 枚举类型的所有值
{
_routes.TryAdd(method.ToString(), new ConcurrentDictionary<string, MethodInfo>()); // 初始化每种 HTTP 方法对应的路由字典
}
// 获取当前程序集
Assembly assembly = Assembly.GetExecutingAssembly();
// 获取包含“Controller”名称的类型
var controllerTypes = assembly.GetTypes()
.Where(t => t.Name.Contains("Controller"));
Type baseAttribute = typeof(AutoHostingAttribute);
Type baseController = typeof(ControllerBase);
foreach (var controllerType in controllerTypes)
{
if (controllerType.IsSubclassOf(baseController) && controllerType.IsDefined(baseAttribute))
{
// 如果属于控制器并标记了AutoHosting特性进行自动注册
AutoRegisterAutoController(controllerType);
}
else
{
continue;
}
}
}
/// <summary>
/// 自动注册 自动实例化控制器 类型
/// </summary>
/// <param name="controllerType"></param>
public void AutoRegisterAutoController(Type controllerType) // 方法声明,用于注册并实例化控制器类型
{
if (!controllerType.IsClass || controllerType.IsAbstract) return; // 如果不是类或者是抽象类,则直接返回
var autoHostingAttribute = controllerType.GetCustomAttribute<AutoHostingAttribute>();
if (autoHostingAttribute != null) {
foreach (var method in controllerType.GetMethods()) // 遍历控制器类型的所有方法
{
var apiGetAttribute = method.GetCustomAttribute<ApiGetAttribute>();
var apiPostAttribute = method.GetCustomAttribute<ApiPostAttribute>();
if( apiGetAttribute == null && apiPostAttribute == null )
{
continue;
}
WebApiAttribute webApiAttribute = new WebApiAttribute()
{
Type = apiGetAttribute != null ? API.GET : API.POST,
Url = apiGetAttribute != null ? apiGetAttribute.Url : apiPostAttribute.Url,
IsUrl = apiGetAttribute != null ? apiGetAttribute.IsUrl : apiPostAttribute.IsUrl,
};
if (apiPostAttribute != null) // 如果存在 WebAPIAttribute 属性
{
var url = AddRoutesUrl(autoHostingAttribute,
webApiAttribute,
controllerType, method);
Console.WriteLine(url);
if (url == null) continue;
_controllerAutoHosting[url] = true;
_controllerTypes[url] = controllerType;
_controllerInstances[url] = null;
}
/* var routeAttribute = method.GetCustomAttribute<WebApiAttribute>(); // 获取方法上的 WebAPIAttribute 自定义属性
if (routeAttribute != null) // 如果存在 WebAPIAttribute 属性
{
var url = AddRoutesUrl(autoHostingAttribute, routeAttribute, controllerType, method);
Console.WriteLine(url);
if (url == null) continue;
_controllerAutoHosting[url] = true;
_controllerTypes[url] = controllerType;
_controllerInstances[url] = null;
}*/
}
}
}
/// <summary>
/// 手动注册 自动实例化控制器实例
/// </summary>
public void RegisterAutoController<T>() // 方法声明,用于动态注册路由
{
Type controllerType = typeof(T); // 获取控制器实例的类型
foreach (var method in controllerType.GetMethods()) // 遍历控制器类型的所有方法
{
var apiGetAttribute = method.GetCustomAttribute<ApiGetAttribute>();
var apiPostAttribute = method.GetCustomAttribute<ApiPostAttribute>();
if (apiGetAttribute == null && apiPostAttribute == null)
{
continue;
}
WebApiAttribute webApiAttribute = new WebApiAttribute()
{
Type = apiGetAttribute != null ? API.GET : API.POST,
Url = apiGetAttribute != null ? apiGetAttribute.Url : apiPostAttribute.Url,
IsUrl = apiGetAttribute != null ? apiGetAttribute.IsUrl : apiPostAttribute.IsUrl,
};
var url = AddRoutesUrl(null, webApiAttribute, controllerType, method);
if (url == null) continue;
_controllerAutoHosting[url] = true;
_controllerTypes[url] = controllerType;
_controllerInstances[url] = null;
}
}
/// <summary>
/// 手动注册 实例持久控制器实例
/// </summary>
/// <param name="controllerInstance"></param>
public void RegisterController<TController>(TController controllerInstance) where TController : ControllerBase // 方法声明,用于动态注册路由
{
if(controllerInstance == null) return;
Type controllerType = controllerInstance.GetType(); // 获取控制器实例的类型
foreach (var method in controllerType.GetMethods()) // 遍历控制器类型的所有方法
{
var apiGetAttribute = method.GetCustomAttribute<ApiGetAttribute>();
var apiPostAttribute = method.GetCustomAttribute<ApiPostAttribute>();
if (apiGetAttribute == null && apiPostAttribute == null)
{
continue;
}
WebApiAttribute webApiAttribute = new WebApiAttribute()
{
Type = apiGetAttribute != null ? API.GET : API.POST,
Url = apiGetAttribute != null ? apiGetAttribute.Url : apiPostAttribute.Url,
IsUrl = apiGetAttribute != null ? apiGetAttribute.IsUrl : apiPostAttribute.IsUrl,
};
var url = AddRoutesUrl(null, webApiAttribute, controllerType, method);
if (url == null) continue;
_controllerInstances[url] = controllerInstance;
_controllerAutoHosting[url] = false;
}
}
/// <summary>
/// 从方法中收集路由信息
/// </summary>
/// <param name="controllerType"></param>
public string AddRoutesUrl(AutoHostingAttribute autoHostingAttribute, WebApiAttribute webAttribute, Type controllerType, MethodInfo method)
{
string controllerName;
if (autoHostingAttribute == null || string.IsNullOrWhiteSpace(autoHostingAttribute.Url))
{
controllerName = controllerType.Name.Replace("Controller", "").ToLower(); // 获取控制器名称并转换为小写
}
else
{
controllerName = autoHostingAttribute.Url;
}
var httpMethod = webAttribute.Type; // 获取 HTTP 方法
var customUrl = webAttribute.Url; // 获取自定义 URL
string url;
if (webAttribute.IsUrl)
{
if (string.IsNullOrEmpty(customUrl)) // 如果自定义 URL 为空
{
url = $"/{controllerName}/{method.Name}".ToLower(); // 构建默认 URL
}
else
{
customUrl = CleanUrl(customUrl);
url = $"/{controllerName}/{method.Name}/{customUrl}".ToLower();// 清理自定义 URL并构建新的 URL
}
_routes[httpMethod.ToString()].TryAdd(url, method); // 将 URL 和方法添加到对应的路由字典中
}
else
{
if (string.IsNullOrEmpty(customUrl)) // 如果自定义 URL 为空
{
url = $"/{controllerName}".ToLower(); // 构建默认 URL
}
else
{
customUrl = CleanUrl(customUrl);
url = $"/{controllerName}/{customUrl}".ToLower();// 清理自定义 URL并构建新的 URL
}
_routes[httpMethod.ToString()].TryAdd(url, method); // 将 URL 和方法添加到对应的路由字典中
}
return url;
}
/// <summary>
/// 收集路由信息
/// </summary>
/// <param name="controllerType"></param>
public void CollectRoutes(Type controllerType)
{
string controllerName = controllerType.Name.Replace("Controller", "").ToLower(); // 获取控制器名称并转换为小写
foreach (var method in controllerType.GetMethods()) // 遍历控制器类型的所有方法
{
var routeAttribute = method.GetCustomAttribute<WebApiAttribute>(); // 获取方法上的 WebAPIAttribute 自定义属性
if (routeAttribute != null) // 如果存在 WebAPIAttribute 属性
{
var customUrl = routeAttribute.Url; // 获取自定义 URL
string url;
if (string.IsNullOrEmpty(customUrl)) // 如果自定义 URL 为空
{
url = $"/api/{controllerName}/{method.Name}".ToLower(); // 构建默认 URL
}
else
{
customUrl = CleanUrl(customUrl);
url = $"/api/{controllerName}/{method.Name}/{customUrl}".ToLower();// 清理自定义 URL并构建新的 URL
}
var httpMethod = routeAttribute.Type; // 获取 HTTP 方法
_routes[httpMethod.ToString()].TryAdd(url, method); // 将 URL 和方法添加到对应的路由字典中
}
}
}
/// <summary>
/// 解析路由,调用对应的方法
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public async Task<bool> RouteAsync(HttpListenerContext context)
{
var request = context.Request; // 获取请求对象
var response = context.Response; // 获取响应对象
var url = request.Url; // 获取请求的 URL
var httpMethod = request.HttpMethod; // 获取请求的 HTTP 方法
var template = request.Url.AbsolutePath.ToLower();
if (!_routes[httpMethod].TryGetValue(template, out MethodInfo method))
{
return false;
}
var routeValues = GetUrlData(url); // 解析 URL 获取路由参数
ControllerBase controllerInstance;
if (!_controllerAutoHosting[template])
{
controllerInstance = (ControllerBase)_controllerInstances[template];
}
else
{
controllerInstance = (ControllerBase)serviceRegistry.Instantiate(_controllerTypes[template]);// 使用反射创建控制器实例
}
if (controllerInstance == null)
{
return false; // 未找到控制器实例
}
controllerInstance.Url = url.AbsolutePath;
object result;
switch (httpMethod) // 根据请求的 HTTP 方法执行不同的操作
{
case "GET": // 如果是 GET 请求传入方法、控制器、url参数
result = InvokeControllerMethodWithRouteValues(method, controllerInstance, routeValues);
break;
case "POST": // POST 请求传入方法、控制器、请求体内容url参数
var requestBody = await ReadRequestBodyAsync(request); // 读取请求体内容
controllerInstance.BobyData = requestBody;
var requestJObject = requestBody.FromJSON<object>();
result = InvokeControllerMethod(method, controllerInstance, requestJObject, routeValues);
break;
default:
result = null;
break;
}
Return(response, result); // 返回结果
return true;
}
public static string GetLog(string Url, string BobyData = "")
{
return Environment.NewLine +
"Url : " + Url + Environment.NewLine +
"Data : " + BobyData + Environment.NewLine;
}
/// <summary>
/// GET请求的控制器方法
/// </summary>
private object InvokeControllerMethodWithRouteValues(MethodInfo method, object controllerInstance, Dictionary<string, string> routeValues)
{
object[] parameters = GetMethodParameters(method, routeValues);
return InvokeMethod(method, controllerInstance, parameters);
}
private static readonly Dictionary<MethodInfo, ParameterInfo[]> methodParameterCache = [];
/// <summary>
/// POST请求的调用控制器方法
/// </summary>
public object InvokeControllerMethod(MethodInfo method, object controllerInstance, dynamic requestData, Dictionary<string, string> routeValues)
{
object?[]? cachedMethodParameters;
if (!methodParameterCache.TryGetValue(method, out ParameterInfo[] parameters))
{
parameters = method.GetParameters();
}
cachedMethodParameters = new object[parameters.Length];
for (int i = 0; i < parameters.Length; i++)
{
string? paramName = parameters[i].Name;
bool isUrlData = parameters[i].GetCustomAttribute(typeof(IsUrlDataAttribute)) != null;
bool isBobyData = parameters[i].GetCustomAttribute(typeof(IsBobyDataAttribute)) != null;
if (isUrlData)
{
if (!string.IsNullOrEmpty(paramName) && routeValues.TryGetValue(paramName, out string? value))
{
cachedMethodParameters[i] = ConvertValue(value, parameters[i].ParameterType);
}
else
{
cachedMethodParameters[i] = null;
}
}
else if (isBobyData)
{
cachedMethodParameters[i] = ConvertValue(requestData.ToString(), parameters[i].ParameterType);
}
else
{
if (requestData.ContainsKey(paramName))
{
if (parameters[i].ParameterType == typeof(string))
{
cachedMethodParameters[i] = requestData[paramName].ToString();
}
else if (parameters[i].ParameterType == typeof(bool))
{
cachedMethodParameters[i] = requestData[paramName?.ToLower()].ToBool();
}
else if (parameters[i].ParameterType == typeof(int))
{
cachedMethodParameters[i] = requestData[paramName].ToInt();
}
else if (parameters[i].ParameterType == typeof(double))
{
cachedMethodParameters[i] = requestData[paramName].ToDouble();
}
else
{
cachedMethodParameters[i] = ConvertValue(requestData[paramName], parameters[i].ParameterType);
}
}
else
{
cachedMethodParameters[i] = null;
}
}
}
// 缓存方法和参数的映射
//methodParameterCache[method] = cachedMethodParameters;
// 调用方法
return method.Invoke(controllerInstance, cachedMethodParameters);
}
/// <summary>
/// 检查方法入参参数类型,返回对应的入参数组
/// </summary>
/// <param name="method"></param>
/// <param name="routeValues"></param>
/// <returns></returns>
private object[] GetMethodParameters(MethodInfo method, Dictionary<string, string> routeValues)
{
ParameterInfo[] methodParameters = method.GetParameters();
object[] parameters = new object[methodParameters.Length];
for (int i = 0; i < methodParameters.Length; i++)
{
string paramName = methodParameters[i].Name;
if (routeValues.TryGetValue(paramName, out string? value))
{
parameters[i] = ConvertValue(value, methodParameters[i].ParameterType);
}
else
{
parameters[i] = null;
}
}
return parameters;
}
/*/// <summary>
/// 转为对应的类型
/// </summary>
/// <param name="value"></param>
/// <param name="targetType"></param>
/// <returns></returns>
private object ConvertValue(object value, Type targetType)
{
try
{
return JsonConvert.DeserializeObject(value.ToString(), targetType);
}
catch (JsonReaderException ex)
{
return value;
}
catch (JsonSerializationException ex)
{
// 如果无法转为对应的JSON对象
int startIndex = ex.Message.IndexOf("to type '") + "to type '".Length; // 查找类型信息开始的索引
int endIndex = ex.Message.IndexOf("'", startIndex); // 查找类型信息结束的索引
var typeInfo = ex.Message.Substring(startIndex, endIndex - startIndex); // 提取出错类型信息,该怎么传出去?
return null;
}
catch // (Exception ex)
{
return value;
}
}*/
/// <summary>
/// 转为对应的类型
/// </summary>
/// <param name="value"></param>
/// <param name="targetType"></param>
/// <returns></returns>
private object ConvertValue(string value, Type targetType)
{
if(targetType == typeof(string))
{
return value;
}
try
{
return JsonConvert.DeserializeObject(value.ToString(), targetType);
}
catch (JsonReaderException ex)
{
return value;
}
catch (JsonSerializationException ex)
{
// 如果无法转为对应的JSON对象
int startIndex = ex.Message.IndexOf("to type '") + "to type '".Length; // 查找类型信息开始的索引
int endIndex = ex.Message.IndexOf('\''); // 查找类型信息结束的索引
var typeInfo = ex.Message[startIndex..endIndex]; // 提取出错类型信息,该怎么传出去?
return null;
}
catch // (Exception ex)
{
return value;
}
}
/// <summary>
/// 调用控制器方法传入参数
/// </summary>
/// <param name="method">方法</param>
/// <param name="controllerInstance">控制器实例</param>
/// <param name="methodParameters">参数列表</param>
/// <returns></returns>
private static object InvokeMethod(MethodInfo method, object controllerInstance, object[] methodParameters)
{
object result = null;
try
{
result = method?.Invoke(controllerInstance, methodParameters);
}
catch (ArgumentException ex)
{
string targetType = ExtractTargetTypeFromExceptionMessage(ex.Message);
// 如果方法调用失败
result = new
{
error = $"函数签名类型[{targetType}]不符合",
};
}
catch (JsonSerializationException ex)
{
// 查找类型信息开始的索引
int startIndex = ex.Message.IndexOf("to type '") + "to type '".Length;
// 查找类型信息结束的索引
int endIndex = ex.Message.IndexOf('\'');
// 提取类型信息
string typeInfo = ex.Message[startIndex..endIndex];
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
return result; // 调用方法并返回结果
}
/// <summary>
/// 方法声明,用于解析 URL 获取路由参数
/// </summary>
/// <param name="uri"></param>
/// <returns></returns>
private static Dictionary<string, string> GetUrlData(Uri uri)
{
Dictionary<string, string> routeValues = [];
var pathParts = uri.ToString().Split('?'); // 拆分 URL获取路径部分
if (pathParts.Length > 1) // 如果包含查询字符串
{
var queryParams = HttpUtility.ParseQueryString(pathParts[1]); // 解析查询字符串
foreach (string key in queryParams) // 遍历查询字符串的键值对
{
if (key == null) continue;
routeValues[key] = queryParams[key]; // 将键值对添加到路由参数字典中
}
}
return routeValues; // 返回路由参数字典
}
/// <summary>
/// 读取Body中的消息
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
private static async Task<string> ReadRequestBodyAsync(HttpListenerRequest request)
{
using Stream stream = request.InputStream;
using StreamReader reader = new(stream, Encoding.UTF8);
return await reader.ReadToEndAsync();
}
/// <summary>
/// 返回响应消息
/// </summary>
/// <param name="response"></param>
/// <param name="msg"></param>
private static void Return(HttpListenerResponse response, dynamic msg)
{
string resultData;
if (response != null)
{
try
{
if (msg is IEnumerable && msg is not string)
{
// If msg is a collection (e.g., array or list), serialize it as JArray
resultData = JArray.FromObject(msg).ToString();
}
else
{
// Otherwise, serialize it as JObject
resultData = JObject.FromObject(msg).ToString();
}
byte[] buffer = Encoding.UTF8.GetBytes(resultData);
response.ContentLength64 = buffer.Length;
response.OutputStream.Write(buffer, 0, buffer.Length);
}
catch
{
// If serialization fails, use the original message's string representation
resultData = msg.ToString();
}
}
}
/// <summary>
/// 解析JSON
/// </summary>
/// <param name="requestBody"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
private static dynamic ParseJson(string requestBody)
{
try
{
if (string.IsNullOrWhiteSpace(requestBody))
{
throw new Exception("Invalid JSON format");
}
return JObject.Parse(requestBody);
}
catch
{
throw new Exception("Invalid JSON format");
}
}
/// <summary>
/// 修正方法特性中的URL格式
/// </summary>
/// <param name="url"></param>
/// <returns></returns>
private static string CleanUrl(string url)
{
while (url.Length > 0 && url[0] == '/') // 去除开头的斜杠
{
url = url[1..];
}
while (url.Length > 0 && url[^1] == '/') // 去除末尾的斜杠
{
url = url[..^1];
}
for (int i = 0; i < url.Length - 1; i++) // 去除连续的斜杠
{
if (url[i] == '/' && url[i + 1] == '/')
{
url = url.Remove(i, 1);
i--;
}
}
return url; // 返回清理后的 URL
}
/// <summary>
/// 从控制器调用方法的异常中获取出出错类型的信息
/// </summary>
/// <param name="errorMessage"></param>
/// <returns></returns>
public static string ExtractTargetTypeFromExceptionMessage(string errorMessage)
{
string targetText = "为类型“";
int startIndex = errorMessage.IndexOf(targetText);
if (startIndex != -1)
{
startIndex += targetText.Length;
int endIndex = errorMessage.IndexOf('\'');
if (endIndex != -1)
{
return errorMessage[startIndex..endIndex];
}
}
return null;
}
}
}

View File

@@ -0,0 +1,187 @@
using Serein.Library.Api.Api;
using Serein.Library.Core.IOC;
using System.Collections.Concurrent;
using System.Net;
namespace Serein.Library.Core.Http
{
/// <summary>
/// HTTP接口监听类
/// </summary>
public class WebServer
{
private readonly HttpListener listener; // HTTP 监听器
private Router router; // 路由器
private readonly RequestLimiter requestLimiter; //接口防刷
public WebServer()
{
listener = new HttpListener();
requestLimiter = new RequestLimiter(5, 8);
}
// 启动服务器
public WebServer Start(string prefixe, ISereinIoc serviceContainer)
{
try
{
router = new Router(serviceContainer);
if (listener.IsListening)
{
return this;
}
if (!prefixe.Substring(prefixe.Length - 1, 1).Equals(@"/"))
{
prefixe += @"/";
}
listener.Prefixes.Add(prefixe); // 添加监听前缀
listener.Start(); // 开始监听
Console.WriteLine($"开始监听:{prefixe}");
Task.Run(async () =>
{
while (listener.IsListening)
{
var context = await listener.GetContextAsync(); // 获取请求上下文
_ = Task.Run(() => ProcessRequestAsync(context)); // 处理请求)
}
});
return this;
}
catch (HttpListenerException ex) when (ex.ErrorCode == 183)
{
return this;
}
}
/// <summary>
/// 处理请求
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
private async Task ProcessRequestAsync(HttpListenerContext context)
{
// 添加CORS头部
context.Response.Headers.Add("Access-Control-Allow-Origin", "*");
context.Response.Headers.Add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
context.Response.Headers.Add("Access-Control-Allow-Headers", "Content-Type");
// 处理OPTIONS预检请求
if (context.Request.HttpMethod == "OPTIONS")
{
context.Response.StatusCode = (int)HttpStatusCode.OK;
context.Response.Close();
return;
}
var isPass = await router.RouteAsync(context); // 路由解析
if (isPass)
{
context.Response.StatusCode = (int)HttpStatusCode.OK;
context.Response.Close(); // 关闭响应
}
else
{
context.Response.StatusCode = (int)HttpStatusCode.NotFound;
context.Response.Close(); // 关闭响应
}
//var isPass = requestLimiter.AllowRequest(context.Request);
//if (isPass)
//{
// // 如果路由没有匹配,返回 404
// router.RouteAsync(context); // 路由解析
//}
//else
//{
// context.Response.StatusCode = (int)HttpStatusCode.NotFound; // 返回 404 错误
// context.Response.Close(); // 关闭响应
//}
// var request = context.Request;
// 获取远程终结点信息
//var remoteEndPoint = context.Request.RemoteEndPoint;
//// 获取用户的IP地址和端口
//IPAddress ipAddress = remoteEndPoint.Address;
//int port = remoteEndPoint.Port;
//Console.WriteLine("外部连接:" + ipAddress.ToString() + ":" + port);
}
// 停止服务器
public void Stop()
{
if (listener.IsListening)
{
listener?.Stop(); // 停止监听
listener?.Close(); // 关闭监听器
}
}
public void RegisterAutoController<T>()
{
//var instance = Activator.CreateInstance(typeof(T));
router.RegisterAutoController<T>();
}
/*public void RegisterRoute<T>(T controllerInstance)
{
router.RegisterRoute(controllerInstance);
}*/
}
/// <summary>
/// 判断访问接口的频次是否正常
/// </summary>
public class RequestLimiter(int seconds, int maxRequests)
{
private readonly ConcurrentDictionary<string, Queue<DateTime>> requestHistory = new ();
private readonly TimeSpan interval = TimeSpan.FromSeconds(seconds);
private readonly int maxRequests = maxRequests;
/// <summary>
/// 判断访问接口的频次是否正常
/// </summary>
/// <returns></returns>
public bool AllowRequest(HttpListenerRequest request)
{
var clientIp = request.RemoteEndPoint.Address.ToString();
var clientPort = request.RemoteEndPoint.Port;
var clientKey = clientIp + ":" + clientPort;
var now = DateTime.Now;
// 尝试从字典中获取请求队列,不存在则创建新的队列
var requests = requestHistory.GetOrAdd(clientKey, new Queue<DateTime>());
lock (requests)
{
// 移除超出时间间隔的请求记录
while (requests.Count > 0 && now - requests.Peek() > interval)
{
requests.Dequeue();
}
// 如果请求数超过限制,拒绝请求
if (requests.Count >= maxRequests)
{
return false;
}
// 添加当前请求时间,并允许请求
requests.Enqueue(now);
}
return true;
}
}
}

View File

@@ -0,0 +1,373 @@
using Serein.Library.Api;
using Serein.Library.Attributes;
using System.Collections.Concurrent;
using System.Reflection;
namespace Serein.Library.Core.IOC
{
public class SereinIoc : ISereinIoc
{
private readonly ConcurrentDictionary<string, object> _dependencies;
private readonly ConcurrentDictionary<string, Type> _typeMappings;
private readonly List<Type> _waitingForInstantiation;
public SereinIoc()
{
_dependencies = new ConcurrentDictionary<string, object>
{
[typeof(ISereinIoc).FullName] = this
};
_typeMappings = new ConcurrentDictionary<string, Type>();
_waitingForInstantiation = [];
}
public object GetOrCreateServiceInstance(Type type, params object[] parameters)
{
Register(type);
object instance;
if (_dependencies.ContainsKey(type.FullName))
{
instance = _dependencies[type.FullName];
}
else
{
instance = Activator.CreateInstance(type);
_dependencies[type.FullName] = instance;
}
return instance;
}
public T CreateServiceInstance<T>(params object[] parameters)
{
return (T)GetOrCreateServiceInstance(typeof(T), parameters);
}
public ISereinIoc Reset()
{
foreach(var instancei in _dependencies.Values)
{
if (typeof(IDisposable).IsAssignableFrom(instancei.GetType()) && instancei is IDisposable disposable)
{
disposable.Dispose();
}
}
_dependencies.Clear();
_waitingForInstantiation.Clear();
//_typeMappings.Clear();
return this;
}
public ISereinIoc Register(Type type, params object[] parameters)
{
if (!_typeMappings.ContainsKey(type.FullName))
{
_typeMappings[type.FullName] = type;
}
return this;
}
public ISereinIoc Register<T>(params object[] parameters)
{
Register(typeof(T), parameters);
return this;
}
public ISereinIoc Register<TService, TImplementation>(params object[] parameters)
where TImplementation : TService
{
_typeMappings[typeof(TService).FullName!] = typeof(TImplementation);
return this;
}
public object GetOrInstantiate(Type type)
{
if (!_dependencies.TryGetValue(type.FullName, out object value))
{
Register(type);
value = Instantiate(type);
InjectDependencies(type);
}
return value;
}
public T GetOrInstantiate<T>()
{
if(!_dependencies.TryGetValue(typeof(T).FullName, out object value))
{
Register<T>();
value = Instantiate(typeof(T));
}
return (T)value;
//throw new InvalidOperationException("目标类型未创建实例");
}
public ISereinIoc Build()
{
foreach (var type in _typeMappings.Values)
{
if(!_dependencies.ContainsKey(type.FullName))
{
_dependencies[type.FullName] = Activator.CreateInstance(type);
}
}
foreach (var instance in _dependencies.Values)
{
InjectDependencies(instance); // 替换占位符
}
//var instance = Instantiate(item.Value);
TryInstantiateWaitingDependencies();
return this;
}
public object? Instantiate(Type controllerType, params object[] parameters)
{
var instance = Activator.CreateInstance(controllerType, parameters);
if(instance != null)
{
InjectDependencies(instance);
}
return instance;
}
private void InjectDependencies(object instance)
{
var properties = instance.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public)
.Where(p => p.CanWrite && p.GetCustomAttribute<AutoInjectionAttribute>() != null);
foreach (var property in properties)
{
var propertyType = property.PropertyType;
if (_dependencies.TryGetValue(propertyType.FullName, out var dependencyInstance))
{
property.SetValue(instance, dependencyInstance);
}
}
}
private void TryInstantiateWaitingDependencies()
{
foreach (var waitingType in _waitingForInstantiation.ToList())
{
if (_typeMappings.TryGetValue(waitingType.FullName!, out var implementationType))
{
var instance = Instantiate(implementationType);
if (instance != null)
{
_dependencies[waitingType.FullName] = instance;
_waitingForInstantiation.Remove(waitingType);
}
}
}
}
#region run()
public ISereinIoc Run<T>(Action<T> action)
{
var service = GetOrInstantiate<T>();
if (service != null)
{
action(service);
}
return this;
}
public ISereinIoc Run<T1, T2>(Action<T1, T2> action)
{
var service1 = GetOrInstantiate<T1>();
var service2 = GetOrInstantiate<T2>();
action(service1, service2);
return this;
}
public ISereinIoc Run<T1, T2, T3>(Action<T1, T2, T3> action)
{
var service1 = GetOrInstantiate<T1>();
var service2 = GetOrInstantiate<T2>();
var service3 = GetOrInstantiate<T3>();
action(service1, service2, service3);
return this;
}
public ISereinIoc Run<T1, T2, T3, T4>(Action<T1, T2, T3, T4> action)
{
var service1 = GetOrInstantiate<T1>();
var service2 = GetOrInstantiate<T2>();
var service3 = GetOrInstantiate<T3>();
var service4 = GetOrInstantiate<T4>();
action(service1, service2, service3, service4);
return this;
}
public ISereinIoc Run<T1, T2, T3, T4, T5>(Action<T1, T2, T3, T4, T5> action)
{
var service1 = GetOrInstantiate<T1>();
var service2 = GetOrInstantiate<T2>();
var service3 = GetOrInstantiate<T3>();
var service4 = GetOrInstantiate<T4>();
var service5 = GetOrInstantiate<T5>();
action(service1, service2, service3, service4, service5);
return this;
}
public ISereinIoc Run<T1, T2, T3, T4, T5, T6>(Action<T1, T2, T3, T4, T5, T6> action)
{
var service1 = GetOrInstantiate<T1>();
var service2 = GetOrInstantiate<T2>();
var service3 = GetOrInstantiate<T3>();
var service4 = GetOrInstantiate<T4>();
var service5 = GetOrInstantiate<T5>();
var service6 = GetOrInstantiate<T6>();
action(service1, service2, service3, service4, service5, service6);
return this;
}
public ISereinIoc Run<T1, T2, T3, T4, T5, T6, T7>(Action<T1, T2, T3, T4, T5, T6, T7> action)
{
var service1 = GetOrInstantiate<T1>();
var service2 = GetOrInstantiate<T2>();
var service3 = GetOrInstantiate<T3>();
var service4 = GetOrInstantiate<T4>();
var service5 = GetOrInstantiate<T5>();
var service6 = GetOrInstantiate<T6>();
var service7 = GetOrInstantiate<T7>();
action(service1, service2, service3, service4, service5, service6, service7);
return this;
}
public ISereinIoc Run<T1, T2, T3, T4, T5, T6, T7, T8>(Action<T1, T2, T3, T4, T5, T6, T7, T8> action)
{
var service1 = GetOrInstantiate<T1>();
var service2 = GetOrInstantiate<T2>();
var service3 = GetOrInstantiate<T3>();
var service4 = GetOrInstantiate<T4>();
var service5 = GetOrInstantiate<T5>();
var service6 = GetOrInstantiate<T6>();
var service7 = GetOrInstantiate<T7>();
var service8 = GetOrInstantiate<T8>();
action(service1, service2, service3, service4, service5, service6, service7, service8);
return this;
}
#endregion
}
/* public interface IServiceContainer
{
ServiceContainer Register<T>(params object[] parameters);
ServiceContainer Register<TService, TImplementation>(params object[] parameters) where TImplementation : TService;
TService Resolve<TService>();
void Get<T>(Action<T> action);
object Instantiate(Type type, params object[] parameters);
}
public class ServiceContainer : IServiceContainer
{
private readonly Dictionary<Type, object> _dependencies;
public ServiceContainer()
{
_dependencies = new Dictionary<Type, object>
{
[typeof(IServiceContainer)] = this
};
}
public void Get<T>(Action<T> action)
{
var service = Resolve<T>();
action(service);
}
public ServiceContainer Register<T>(params object[] parameters)
{
var instance = Instantiate(typeof(T), parameters);
_dependencies[typeof(T)] = instance;
return this;
}
public ServiceContainer Register<TService, TImplementation>(params object[] parameters)
where TImplementation : TService
{
_dependencies[typeof(TService)] = Instantiate(typeof(TImplementation), parameters);
return this;
}
public TService Resolve<TService>()
{
return (TService)_dependencies[typeof(TService)];
}
public object Instantiate(Type controllerType, params object[] parameters)
{
var constructors = controllerType.GetConstructors(); // 获取控制器的所有构造函数
// 查找具有最多参数的构造函数
var constructor = constructors.OrderByDescending(c => c.GetParameters().Length).FirstOrDefault();
if (constructor != null)
{
if (parameters.Length > 0)
{
return Activator.CreateInstance(controllerType, parameters);
}
else {
var tmpParameters = constructor.GetParameters();
var dependencyInstances = new List<object>();
foreach (var parameter in tmpParameters)
{
var parameterType = parameter.ParameterType;
_dependencies.TryGetValue(parameterType, out var dependencyInstance);
dependencyInstances.Add(dependencyInstance);
if (dependencyInstance == null)
{
return null;
}
}
// 用解析的依赖项实例化目标类型
return Activator.CreateInstance(controllerType, dependencyInstances.ToArray());
}
}
else
{
return Activator.CreateInstance(controllerType);
}
}
}*/
}

View File

@@ -0,0 +1,35 @@
using Serein.Library.Api;
using Serein.Library.Utils;
namespace Serein.Library.Core.NodeFlow
{
/// <summary>
/// 动态流程上下文
/// </summary>
public class DynamicContext: IDynamicContext
{
public DynamicContext(ISereinIoc sereinIoc)
{
SereinIoc = sereinIoc;
}
public NodeRunCts NodeRunCts { get; set; }
public ISereinIoc SereinIoc { get; }
public Task CreateTimingTask(Action action, int time = 100, int count = -1)
{
NodeRunCts ??= SereinIoc.GetOrInstantiate<NodeRunCts>();
return Task.Factory.StartNew(async () =>
{
for (int i = 0; i < count; i++)
{
NodeRunCts.Token.ThrowIfCancellationRequested();
await Task.Delay(time);
action.Invoke();
}
});
}
}
}

View File

@@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Serein.LibraryCore.NodeFlow
{
public enum DynamicNodeCoreType
{
/// <summary>
/// 初始化
/// </summary>
Init,
/// <summary>
/// 开始载入
/// </summary>
Loading,
/// <summary>
/// 结束
/// </summary>
Exit,
/// <summary>
/// 触发器
/// </summary>
Flipflop,
/// <summary>
/// 条件节点
/// </summary>
Condition,
/// <summary>
/// 动作节点
/// </summary>
Action,
}
}

View File

@@ -0,0 +1,85 @@
using Serein.Library.Api;
using Serein.Library.Enums;
namespace Serein.Library.Core.NodeFlow
{
public static class FlipflopFunc
{
/// <summary>
/// 传入触发器方法的返回类型尝试获取Task[Flipflop[]] 中的泛型类型
/// </summary>
//public static Type GetFlipflopInnerType(Type type)
//{
// // 检查是否为泛型类型且为 Task<>
// if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Task<>))
// {
// // 获取 Task<> 的泛型参数类型,即 Flipflop<>
// var innerType = type.GetGenericArguments()[0];
// // 检查泛型参数是否为 Flipflop<>
// if (innerType.IsGenericType && innerType.GetGenericTypeDefinition() == typeof(FlipflopContext<>))
// {
// // 获取 Flipflop<> 的泛型参数类型,即 T
// var flipflopInnerType = innerType.GetGenericArguments()[0];
// // 返回 Flipflop<> 中的具体类型
// return flipflopInnerType;
// }
// }
// // 如果不符合条件,返回 null
// return null;
//}
public static bool IsTaskOfFlipflop(Type type)
{
// 检查是否为泛型类型且为 Task<>
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Task<>))
{
// 获取 Task<> 的泛型参数类型
var innerType = type.GetGenericArguments()[0];
// 判断 innerType 是否继承 IFlipflopContext
//if (typeof(IFlipflopContext).IsAssignableFrom(innerType))
//{
// return true;
//}
//else
//{
// return false;
//}
// 检查泛型参数是否为 Flipflop<>
if (innerType == typeof(IFlipflopContext))
//if (innerType.IsGenericType && innerType.GetGenericTypeDefinition() == typeof(FlipflopContext<>))
{
return true;
}
}
return false;
}
}
/// <summary>
/// 触发器上下文
/// </summary>
public class FlipflopContext : IFlipflopContext
{
public FlowStateType State { get; set; }
//public TResult? Data { get; set; }
public object Data { get; set; }
public FlipflopContext(FlowStateType ffState)
{
State = ffState;
}
public FlipflopContext(FlowStateType ffState, object data)
{
State = ffState;
Data = data;
}
}
}

View File

@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Serein.Library.Core.NodeFlow
{
//public enum FlowStateType
//{
// /// <summary>
// /// 成功(方法成功执行)
// /// </summary>
// Succeed,
// /// <summary>
// /// 失败(方法没有成功执行,不过执行时没有发生非预期的错误)
// /// </summary>
// Fail,
// /// <summary>
// /// 异常(节点没有成功执行,执行时发生非预期的错误)
// /// </summary>
// Error,
//}
}

View File

@@ -0,0 +1,35 @@
using Serein.Library.Api.Enums;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Serein.Library.Core.NodeFlow.Tool
{
/// <summary>
/// 用来判断一个类是否需要注册并构建实例(单例模式场景使用)
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class DynamicFlowAttribute(bool scan = true) : Attribute
{
public bool Scan { get; set; } = scan;
}
/// <summary>
/// 标记一个方法是什么类型加载dll后用来拖拽到画布中
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class MethodDetailAttribute(DynamicNodeType methodDynamicType,
string methodTips = "",
bool scan = true,
string lockName = "") : Attribute
{
public bool Scan { get; set; } = scan;
public string MethodTips { get; } = methodTips;
public DynamicNodeType MethodDynamicType { get; } = methodDynamicType;
public string LockName { get; } = lockName;
}
}

View File

@@ -0,0 +1,202 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Drawing.Printing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Serein.Library.Core.NodeFlow.Tool
{
#region tsk工具 (
/*public class LockManager
{
private readonly ConcurrentDictionary<string, LockQueue> _locks = new ConcurrentDictionary<string, LockQueue>();
public void CreateLock(string name)
{
_locks.TryAdd(name, new LockQueue());
}
public async Task AcquireLockAsync(string name, CancellationToken cancellationToken = default)
{
if (!_locks.ContainsKey(name))
{
throw new ArgumentException($"Lock with name '{name}' does not exist.");
}
var lockQueue = _locks[name];
var tcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
lock (lockQueue.Queue)
{
lockQueue.Queue.Enqueue(tcs);
if (lockQueue.Queue.Count == 1)
{
tcs.SetResult(true);
}
}
await tcs.Task.ConfigureAwait(false);
// 处理取消操作
if (cancellationToken.CanBeCanceled)
{
cancellationToken.Register(() =>
{
lock (lockQueue.Queue)
{
if (lockQueue.Queue.Contains(tcs))
{
tcs.TrySetCanceled();
}
}
});
}
}
public void ReleaseLock(string name)
{
if (!_locks.ContainsKey(name))
{
throw new ArgumentException($"Lock with name '{name}' does not exist.");
}
var lockQueue = _locks[name];
lock (lockQueue.Queue)
{
if (lockQueue.Queue.Count > 0)
{
lockQueue.Queue.Dequeue();
if (lockQueue.Queue.Count > 0)
{
var next = lockQueue.Queue.Peek();
next.SetResult(true);
}
}
}
}
private class LockQueue
{
public Queue<TaskCompletionSource<bool>> Queue { get; } = new Queue<TaskCompletionSource<bool>>();
}
}
public interface ITaskResult
{
object Result { get; }
}
public class TaskResult<T> : ITaskResult
{
public TaskResult(T result)
{
Result = result;
}
public T Result { get; }
object ITaskResult.Result => Result;
}
public class DynamicTasks
{
private static readonly ConcurrentDictionary<string, Task<ITaskResult>> TaskGuidPairs = new();
public static Task<ITaskResult> GetTask(string Guid)
{
TaskGuidPairs.TryGetValue(Guid, out Task<ITaskResult> task);
return task;
}
public static bool AddTask<T>(string Guid, T result)
{
var task = Task.FromResult<ITaskResult>(new TaskResult<T>(result));
return TaskGuidPairs.TryAdd(Guid, task);
}
}
public class TaskNodeManager
{
private readonly ConcurrentDictionary<string, TaskQueue> _taskQueues = new ConcurrentDictionary<string, TaskQueue>();
public void CreateTaskNode(string name)
{
_taskQueues.TryAdd(name, new TaskQueue());
}
public async Task WaitForTaskNodeAsync(string name, CancellationToken cancellationToken = default)
{
if (!_taskQueues.ContainsKey(name))
{
throw new ArgumentException($"Task node with name '{name}' does not exist.");
}
var taskQueue = _taskQueues[name];
var tcs = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
lock (taskQueue.Queue)
{
taskQueue.Queue.Enqueue(tcs);
if (taskQueue.Queue.Count == 1)
{
tcs.SetResult(true);
}
}
await tcs.Task.ConfigureAwait(false);
// 处理取消操作
if (cancellationToken.CanBeCanceled)
{
cancellationToken.Register(() =>
{
lock (taskQueue.Queue)
{
if (taskQueue.Queue.Contains(tcs))
{
tcs.TrySetCanceled();
}
}
});
}
}
public void CompleteTaskNode(string name)
{
if (!_taskQueues.ContainsKey(name))
{
throw new ArgumentException($"Task node with name '{name}' does not exist.");
}
var taskQueue = _taskQueues[name];
lock (taskQueue.Queue)
{
if (taskQueue.Queue.Count > 0)
{
taskQueue.Queue.Dequeue();
if (taskQueue.Queue.Count > 0)
{
var next = taskQueue.Queue.Peek();
next.SetResult(true);
}
}
}
}
private class TaskQueue
{
public Queue<TaskCompletionSource<bool>> Queue { get; } = new Queue<TaskCompletionSource<bool>>();
}
}*/
#endregion
}

View File

@@ -0,0 +1,52 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0-windows7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<BaseOutputPath>D:\Project\C#\DynamicControl\SereinFlow\.Output</BaseOutputPath>
<OutputType>Library</OutputType>
</PropertyGroup>
<ItemGroup>
<Compile Remove="DbSql\**" />
<Compile Remove="Flow\**" />
<Compile Remove="Http\**" />
<Compile Remove="IOC\**" />
<Compile Remove="NodeFlow\Tool\**" />
<Compile Remove="obj\**" />
<Compile Remove="SerinExpression\**" />
<Compile Remove="Tool\**" />
<EmbeddedResource Remove="DbSql\**" />
<EmbeddedResource Remove="Flow\**" />
<EmbeddedResource Remove="Http\**" />
<EmbeddedResource Remove="IOC\**" />
<EmbeddedResource Remove="NodeFlow\Tool\**" />
<EmbeddedResource Remove="obj\**" />
<EmbeddedResource Remove="SerinExpression\**" />
<EmbeddedResource Remove="Tool\**" />
<None Remove="DbSql\**" />
<None Remove="Flow\**" />
<None Remove="Http\**" />
<None Remove="IOC\**" />
<None Remove="NodeFlow\Tool\**" />
<None Remove="obj\**" />
<None Remove="SerinExpression\**" />
<None Remove="Tool\**" />
</ItemGroup>
<ItemGroup>
<Compile Remove="NodeFlow\DynamicNodeCoreType.cs" />
<Compile Remove="NodeFlow\FlowStateType.cs" />
<Compile Remove="ServiceContainer.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Library\Serein.Library.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,337 @@
using System.Reflection;
namespace Serein.LibraryCore.SerinExpression
{
/// <summary>
/// 条件解析抽象类
/// </summary>
public abstract class ConditionResolver
{
public abstract bool Evaluate(object obj);
}
public class PassConditionResolver : ConditionResolver
{
public Operator Op { get; set; }
public override bool Evaluate(object obj)
{
return Op switch
{
Operator.Pass => true,
Operator.NotPass => false,
_ => throw new NotSupportedException("不支持的条件类型")
};
}
public enum Operator
{
Pass,
NotPass,
}
}
public class ValueTypeConditionResolver<T> : ConditionResolver where T : struct, IComparable<T>
{
public enum Operator
{
/// <summary>
/// 不进行任何操作
/// </summary>
Node,
/// <summary>
/// 大于
/// </summary>
GreaterThan,
/// <summary>
/// 小于
/// </summary>
LessThan,
/// <summary>
/// 等于
/// </summary>
Equal,
/// <summary>
/// 大于或等于
/// </summary>
GreaterThanOrEqual,
/// <summary>
/// 小于或等于
/// </summary>
LessThanOrEqual,
/// <summary>
/// 在两者之间
/// </summary>
InRange,
/// <summary>
/// 不在两者之间
/// </summary>
OutOfRange
}
public Operator Op { get; set; }
public T Value { get; set; }
public T RangeStart { get; set; }
public T RangeEnd { get; set; }
public string ArithmeticExpression { get; set; }
public override bool Evaluate(object obj)
{
if (obj is T typedObj)
{
double numericValue = Convert.ToDouble(typedObj);
if (!string.IsNullOrEmpty(ArithmeticExpression))
{
numericValue = SerinArithmeticExpressionEvaluator.Evaluate(ArithmeticExpression, numericValue);
}
T evaluatedValue = (T)Convert.ChangeType(numericValue, typeof(T));
return Op switch
{
Operator.GreaterThan => evaluatedValue.CompareTo(Value) > 0,
Operator.LessThan => evaluatedValue.CompareTo(Value) < 0,
Operator.Equal => evaluatedValue.CompareTo(Value) == 0,
Operator.GreaterThanOrEqual => evaluatedValue.CompareTo(Value) >= 0,
Operator.LessThanOrEqual => evaluatedValue.CompareTo(Value) <= 0,
Operator.InRange => evaluatedValue.CompareTo(RangeStart) >= 0 && evaluatedValue.CompareTo(RangeEnd) <= 0,
Operator.OutOfRange => evaluatedValue.CompareTo(RangeStart) < 0 || evaluatedValue.CompareTo(RangeEnd) > 0,
_ => throw new NotSupportedException("不支持的条件类型")
};
/* switch (Op)
{
case Operator.GreaterThan:
return evaluatedValue.CompareTo(Value) > 0;
case Operator.LessThan:
return evaluatedValue.CompareTo(Value) < 0;
case Operator.Equal:
return evaluatedValue.CompareTo(Value) == 0;
case Operator.GreaterThanOrEqual:
return evaluatedValue.CompareTo(Value) >= 0;
case Operator.LessThanOrEqual:
return evaluatedValue.CompareTo(Value) <= 0;
case Operator.InRange:
return evaluatedValue.CompareTo(RangeStart) >= 0 && evaluatedValue.CompareTo(RangeEnd) <= 0;
case Operator.OutOfRange:
return evaluatedValue.CompareTo(RangeStart) < 0 || evaluatedValue.CompareTo(RangeEnd) > 0;
}*/
}
return false;
}
}
public class BoolConditionResolver : ConditionResolver
{
public enum Operator
{
/// <summary>
/// 是
/// </summary>
Is
}
public Operator Op { get; set; }
public bool Value { get; set; }
public override bool Evaluate(object obj)
{
if (obj is bool boolObj)
{
return boolObj == Value;
/*switch (Op)
{
case Operator.Is:
return boolObj == Value;
}*/
}
return false;
}
}
public class StringConditionResolver : ConditionResolver
{
public enum Operator
{
/// <summary>
/// 出现过
/// </summary>
Contains,
/// <summary>
/// 没有出现过
/// </summary>
DoesNotContain,
/// <summary>
/// 相等
/// </summary>
Equal,
/// <summary>
/// 不相等
/// </summary>
NotEqual,
/// <summary>
/// 起始字符串等于
/// </summary>
StartsWith,
/// <summary>
/// 结束字符串等于
/// </summary>
EndsWith
}
public Operator Op { get; set; }
public string Value { get; set; }
public override bool Evaluate(object obj)
{
if (obj is string strObj)
{
return Op switch
{
Operator.Contains => strObj.Contains(Value),
Operator.DoesNotContain => !strObj.Contains(Value),
Operator.Equal => strObj == Value,
Operator.NotEqual => strObj != Value,
Operator.StartsWith => strObj.StartsWith(Value),
Operator.EndsWith => strObj.EndsWith(Value),
_ => throw new NotSupportedException("不支持的条件类型"),
};
/* switch (Op)
{
case Operator.Contains:
return strObj.Contains(Value);
case Operator.DoesNotContain:
return !strObj.Contains(Value);
case Operator.Equal:
return strObj == Value;
case Operator.NotEqual:
return strObj != Value;
case Operator.StartsWith:
return strObj.StartsWith(Value);
case Operator.EndsWith:
return strObj.EndsWith(Value);
}*/
}
return false;
}
}
public class MemberConditionResolver<T> : ConditionResolver where T : struct, IComparable<T>
{
//public string MemberPath { get; set; }
public ValueTypeConditionResolver<T>.Operator Op { get; set; }
public object? TargetObj { get; set; }
public T Value { get; set; }
public string ArithmeticExpression { get; set; }
public override bool Evaluate(object? obj)
{
//object? memberValue = GetMemberValue(obj, MemberPath);
if (TargetObj is T typedObj)
{
return new ValueTypeConditionResolver<T>
{
Op = Op,
Value = Value,
ArithmeticExpression = ArithmeticExpression,
}.Evaluate(typedObj);
}
return false;
}
//private object? GetMemberValue(object? obj, string memberPath)
//{
// string[] members = memberPath[1..].Split('.');
// foreach (var member in members)
// {
// if (obj == null) return null;
// Type type = obj.GetType();
// PropertyInfo? propertyInfo = type.GetProperty(member);
// FieldInfo? fieldInfo = type.GetField(member);
// if (propertyInfo != null)
// obj = propertyInfo.GetValue(obj);
// else if (fieldInfo != null)
// obj = fieldInfo.GetValue(obj);
// else
// throw new ArgumentException($"Member {member} not found in type {type.FullName}");
// }
// return obj;
//}
}
public class MemberStringConditionResolver : ConditionResolver
{
public string MemberPath { get; set; }
public StringConditionResolver.Operator Op { get; set; }
public string Value { get; set; }
public override bool Evaluate(object obj)
{
object memberValue = GetMemberValue(obj, MemberPath);
if (memberValue is string strObj)
{
return new StringConditionResolver
{
Op = Op,
Value = Value
}.Evaluate(strObj);
}
return false;
}
private object GetMemberValue(object? obj, string memberPath)
{
string[] members = memberPath[1..].Split('.');
foreach (var member in members)
{
if (obj == null) return null;
Type type = obj.GetType();
PropertyInfo? propertyInfo = type.GetProperty(member);
FieldInfo? fieldInfo = type.GetField(member);
if (propertyInfo != null)
obj = propertyInfo.GetValue(obj);
else if (fieldInfo != null)
obj = fieldInfo.GetValue(obj);
else
throw new ArgumentException($"Member {member} not found in type {type.FullName}");
}
return obj;
}
private static string GetArithmeticExpression(string part)
{
int startIndex = part.IndexOf('[');
int endIndex = part.IndexOf(']');
if (startIndex >= 0 && endIndex > startIndex)
{
return part.Substring(startIndex + 1, endIndex - startIndex - 1);
}
return null;
}
}
}

View File

@@ -0,0 +1,338 @@
using System.Globalization;
using System.Reflection;
namespace Serein.LibraryCore.SerinExpression;
public class SerinConditionParser
{
public static bool To<T>(T data, string expression)
{
try
{
return ConditionParse(data, expression).Evaluate(data);
}
catch (Exception ex)
{
Console.WriteLine(ex);
throw;
}
}
public static ConditionResolver ConditionParse(object data, string expression)
{
if (expression.StartsWith('.')) // 表达式前缀属于从上一个节点数据对象获取成员值
{
return ParseObjectExpression(data, expression);
}
else
{
return ParseSimpleExpression(data, expression);
}
//bool ContainsArithmeticOperators(string expression)
//{
// return expression.Contains('+') || expression.Contains('-') || expression.Contains('*') || expression.Contains('/');
//}
}
/// <summary>
/// 获取计算表达式的部分
/// </summary>
/// <param name="part"></param>
/// <returns></returns>
private static string GetArithmeticExpression(string part)
{
int startIndex = part.IndexOf('[');
int endIndex = part.IndexOf(']');
if (startIndex >= 0 && endIndex > startIndex)
{
return part.Substring(startIndex + 1, endIndex - startIndex - 1);
}
return null;
}
/// <summary>
/// 获取对象指定名称的成员
/// </summary>
private static object? GetMemberValue(object? obj, string memberPath)
{
string[] members = memberPath[1..].Split('.');
foreach (var member in members)
{
if (obj == null) return null;
Type type = obj.GetType();
PropertyInfo? propertyInfo = type.GetProperty(member);
FieldInfo? fieldInfo = type.GetField(member);
if (propertyInfo != null)
obj = propertyInfo.GetValue(obj);
else if (fieldInfo != null)
obj = fieldInfo.GetValue(obj);
else
throw new ArgumentException($"Member {member} not found in type {type.FullName}");
}
return obj;
}
/// <summary>
/// 解析对象表达式
/// </summary>
private static ConditionResolver ParseObjectExpression(object data, string expression)
{
var parts = expression.Split(' ');
string operatorStr = parts[0];
string valueStr = string.Join(' ', parts, 1, parts.Length - 1);
int typeStartIndex = expression.IndexOf('<');
int typeEndIndex = expression.IndexOf('>');
string memberPath;
Type type;
object? targetObj;
if (typeStartIndex + typeStartIndex == -2)
{
memberPath = operatorStr;
targetObj = GetMemberValue(data, operatorStr);
type = targetObj.GetType();
operatorStr = parts[1].ToLower();
valueStr = string.Join(' ', parts.Skip(2));
}
else
{
if (typeStartIndex >= typeEndIndex)
{
throw new ArgumentException("无效的表达式格式");
}
memberPath = expression.Substring(0, typeStartIndex).Trim();
string typeStr = expression.Substring(typeStartIndex + 1, typeEndIndex - typeStartIndex - 1).Trim().ToLower();
parts = expression.Substring(typeEndIndex + 1).Trim().Split(' ');
if (parts.Length == 3)
{
operatorStr = parts[1].ToLower();
valueStr = string.Join(' ', parts.Skip(2));
}
else
{
operatorStr = parts[0].ToLower();
valueStr = string.Join(' ', parts.Skip(1));
}
targetObj = GetMemberValue(data, memberPath);
Type? tempType = typeStr switch
{
"int" => typeof(int),
"double" => typeof(double),
"bool" => typeof(bool),
"string" => typeof(string),
_ => Type.GetType(typeStr)
};
type = tempType ?? throw new ArgumentException("对象表达式无效的类型声明");
}
if (type == typeof(int))
{
int value = int.Parse(valueStr, CultureInfo.InvariantCulture);
return new MemberConditionResolver<int>
{
TargetObj = targetObj,
//MemberPath = memberPath,
Op = ParseValueTypeOperator<int>(operatorStr),
Value = value,
ArithmeticExpression = GetArithmeticExpression(parts[0])
};
}
else if (type == typeof(double))
{
double value = double.Parse(valueStr, CultureInfo.InvariantCulture);
return new MemberConditionResolver<double>
{
//MemberPath = memberPath,
TargetObj = targetObj,
Op = ParseValueTypeOperator<double>(operatorStr),
Value = value,
ArithmeticExpression = GetArithmeticExpression(parts[0])
};
}
else if (type == typeof(bool))
{
return new MemberConditionResolver<bool>
{
//MemberPath = memberPath,
TargetObj = targetObj,
Op = (ValueTypeConditionResolver<bool>.Operator)ParseBoolOperator(operatorStr)
};
}
else if (type == typeof(string))
{
return new MemberStringConditionResolver
{
MemberPath = memberPath,
Op = ParseStringOperator(operatorStr),
Value = valueStr
};
}
throw new NotSupportedException($"Type {type} is not supported.");
}
private static ConditionResolver ParseSimpleExpression(object data, string expression)
{
if ("pass".Equals(expression.ToLower()))
{
return new PassConditionResolver
{
Op = PassConditionResolver.Operator.Pass,
};
}
else
{
if ("not pass".Equals(expression.ToLower()))
{
return new PassConditionResolver
{
Op = PassConditionResolver.Operator.NotPass,
};
}
if ("!pass".Equals(expression.ToLower()))
{
return new PassConditionResolver
{
Op = PassConditionResolver.Operator.NotPass,
};
}
}
var parts = expression.Split(' ');
if (parts.Length < 2)
throw new ArgumentException("无效的表达式格式。");
//string typeStr = parts[0];
string operatorStr = parts[0];
string valueStr = string.Join(' ', parts, 1, parts.Length - 1);
Type type = data.GetType();//Type.GetType(typeStr);
if (type == typeof(int))
{
var op = ParseValueTypeOperator<int>(operatorStr);
if (op == ValueTypeConditionResolver<int>.Operator.InRange || op == ValueTypeConditionResolver<int>.Operator.OutOfRange)
{
var temp = valueStr.Split('-');
if (temp.Length < 2)
throw new ArgumentException($"范围无效:{valueStr}。");
int rangeStart = int.Parse(temp[0], CultureInfo.InvariantCulture);
int rangeEnd = int.Parse(temp[1], CultureInfo.InvariantCulture);
return new ValueTypeConditionResolver<int>
{
Op = op,
RangeStart = rangeStart,
RangeEnd = rangeEnd,
ArithmeticExpression = GetArithmeticExpression(parts[0]),
};
}
else
{
int value = int.Parse(valueStr, CultureInfo.InvariantCulture);
return new ValueTypeConditionResolver<int>
{
Op = op,
Value = value,
ArithmeticExpression = GetArithmeticExpression(parts[0])
};
}
}
else if (type == typeof(double))
{
double value = double.Parse(valueStr, CultureInfo.InvariantCulture);
return new ValueTypeConditionResolver<double>
{
Op = ParseValueTypeOperator<double>(operatorStr),
Value = value,
ArithmeticExpression = GetArithmeticExpression(parts[0])
};
}
else if (type == typeof(bool))
{
bool value = bool.Parse(valueStr);
return new BoolConditionResolver
{
Op = ParseBoolOperator(operatorStr),
Value = value,
};
}
else if (type == typeof(string))
{
return new StringConditionResolver
{
Op = ParseStringOperator(operatorStr),
Value = valueStr
};
}
throw new NotSupportedException($"Type {type} is not supported.");
}
private static ValueTypeConditionResolver<T>.Operator ParseValueTypeOperator<T>(string operatorStr) where T : struct, IComparable<T>
{
return operatorStr switch
{
">" => ValueTypeConditionResolver<T>.Operator.GreaterThan,
"<" => ValueTypeConditionResolver<T>.Operator.LessThan,
"=" => ValueTypeConditionResolver<T>.Operator.Equal,
"==" => ValueTypeConditionResolver<T>.Operator.Equal,
">=" => ValueTypeConditionResolver<T>.Operator.GreaterThanOrEqual,
"≥" => ValueTypeConditionResolver<T>.Operator.GreaterThanOrEqual,
"<=" => ValueTypeConditionResolver<T>.Operator.LessThanOrEqual,
"≤" => ValueTypeConditionResolver<T>.Operator.LessThanOrEqual,
"equals" => ValueTypeConditionResolver<T>.Operator.Equal,
"in" => ValueTypeConditionResolver<T>.Operator.InRange,
"!in" => ValueTypeConditionResolver<T>.Operator.OutOfRange,
_ => throw new ArgumentException($"Invalid operator {operatorStr} for value type.")
};
}
private static BoolConditionResolver.Operator ParseBoolOperator(string operatorStr)
{
return operatorStr switch
{
"is" => BoolConditionResolver.Operator.Is,
"==" => BoolConditionResolver.Operator.Is,
"equals" => BoolConditionResolver.Operator.Is,
//"isFalse" => BoolConditionNode.Operator.IsFalse,
_ => throw new ArgumentException($"Invalid operator {operatorStr} for bool type.")
};
}
private static StringConditionResolver.Operator ParseStringOperator(string operatorStr)
{
return operatorStr switch
{
"c" => StringConditionResolver.Operator.Contains,
"nc" => StringConditionResolver.Operator.DoesNotContain,
"sw" => StringConditionResolver.Operator.StartsWith,
"ew" => StringConditionResolver.Operator.EndsWith,
"contains" => StringConditionResolver.Operator.Contains,
"doesNotContain" => StringConditionResolver.Operator.DoesNotContain,
"equals" => StringConditionResolver.Operator.Equal,
"==" => StringConditionResolver.Operator.Equal,
"notEquals" => StringConditionResolver.Operator.NotEqual,
"!=" => StringConditionResolver.Operator.NotEqual,
"startsWith" => StringConditionResolver.Operator.StartsWith,
"endsWith" => StringConditionResolver.Operator.EndsWith,
_ => throw new ArgumentException($"Invalid operator {operatorStr} for string type.")
};
}
}

View File

@@ -0,0 +1,216 @@
using System.Data;
namespace Serein.LibraryCore.SerinExpression
{
public class SerinArithmeticExpressionEvaluator
{
private static readonly DataTable table = new DataTable();
public static double Evaluate(string expression, double inputValue)
{
// 替换占位符@为输入值
expression = expression.Replace("@", inputValue.ToString());
try
{
// 使用 DataTable.Compute 方法计算表达式
var result = table.Compute(expression, string.Empty);
return Convert.ToDouble(result);
}
catch
{
throw new ArgumentException("Invalid arithmetic expression.");
}
}
}
public class SerinExpressionEvaluator
{
/// <summary>
///
/// </summary>
/// <param name="expression">表达式</param>
/// <param name="targetObJ">操作对象</param>
/// <param name="isChange">是否改变了对象get语法</param>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
/// <exception cref="NotSupportedException"></exception>
public static object Evaluate(string expression, object targetObJ, out bool isChange)
{
var parts = expression.Split([' '], 2);
if (parts.Length != 2)
{
throw new ArgumentException("Invalid expression format.");
}
var operation = parts[0].ToLower();
var operand = parts[1][0] == '.' ? parts[1][1..] : parts[1];
var result = operation switch
{
"@num" => ComputedNumber(targetObJ, operand),
"@call" => InvokeMethod(targetObJ, operand),
"@get" => GetMember(targetObJ, operand),
"@set" => SetMember(targetObJ, operand),
_ => throw new NotSupportedException($"Operation {operation} is not supported.")
};
isChange = operation switch
{
"@num" => true,
"@call" => true,
"@get" => true,
"@set" => false,
_ => throw new NotSupportedException($"Operation {operation} is not supported.")
};
return result;
}
private static readonly char[] separator = ['(', ')'];
private static readonly char[] separatorArray = [','];
private static object InvokeMethod(object target, string methodCall)
{
var methodParts = methodCall.Split(separator, StringSplitOptions.RemoveEmptyEntries);
if (methodParts.Length != 2)
{
throw new ArgumentException("Invalid method call format.");
}
var methodName = methodParts[0];
var parameterList = methodParts[1];
var parameters = parameterList.Split(separatorArray, StringSplitOptions.RemoveEmptyEntries)
.Select(p => p.Trim())
.ToArray();
var method = target.GetType().GetMethod(methodName);
if (method == null)
{
throw new ArgumentException($"Method {methodName} not found on target.");
}
var parameterValues = method.GetParameters()
.Select((p, index) => Convert.ChangeType(parameters[index], p.ParameterType))
.ToArray();
return method.Invoke(target, parameterValues);
}
private static object GetMember(object target, string memberPath)
{
var members = memberPath.Split('.');
foreach (var member in members)
{
if (target == null) return null;
var property = target.GetType().GetProperty(member);
if (property != null)
{
target = property.GetValue(target);
}
else
{
var field = target.GetType().GetField(member);
if (field != null)
{
target = field.GetValue(target);
}
else
{
throw new ArgumentException($"Member {member} not found on target.");
}
}
}
return target;
}
private static object SetMember(object target, string assignment)
{
var parts = assignment.Split(new[] { '=' }, 2);
if (parts.Length != 2)
{
throw new ArgumentException("Invalid assignment format.");
}
var memberPath = parts[0].Trim();
var value = parts[1].Trim();
var members = memberPath.Split('.');
for (int i = 0; i < members.Length - 1; i++)
{
var member = members[i];
var property = target.GetType().GetProperty(member);
if (property != null)
{
target = property.GetValue(target);
}
else
{
var field = target.GetType().GetField(member);
if (field != null)
{
target = field.GetValue(target);
}
else
{
throw new ArgumentException($"Member {member} not found on target.");
}
}
}
var lastMember = members.Last();
var lastProperty = target.GetType().GetProperty(lastMember);
if (lastProperty != null)
{
var convertedValue = Convert.ChangeType(value, lastProperty.PropertyType);
lastProperty.SetValue(target, convertedValue);
}
else
{
var lastField = target.GetType().GetField(lastMember);
if (lastField != null)
{
var convertedValue = Convert.ChangeType(value, lastField.FieldType);
lastField.SetValue(target, convertedValue);
}
else
{
throw new ArgumentException($"Member {lastMember} not found on target.");
}
}
return target;
}
private static double ComputedNumber(object value, string expression)
{
double numericValue = Convert.ToDouble(value);
if (!string.IsNullOrEmpty(expression))
{
numericValue = SerinArithmeticExpressionEvaluator.Evaluate(expression, numericValue);
}
return numericValue;
}
}
}

View File

@@ -0,0 +1,418 @@
//using Serein.Web;
//using Microsoft.Win32;
//using NetTaste;
//using System.Collections.Concurrent;
//using System.Reflection;
//using System;
//using System.Linq;
//using System.Collections.Generic;
//using SqlSugar;
//namespace Serein
//{
// public interface IServiceContainer
// {
// /// <summary>
// /// 获取或创建类型的实例(不注入依赖项)
// /// </summary>
// object GetOrCreateServiceInstance(Type serviceType, params object[] parameters);
// T CreateServiceInstance<T>(params object[] parameters);
// IServiceContainer Reset(); // 清空
// IServiceContainer Register(Type type, params object[] parameters);
// IServiceContainer Register<T>(params object[] parameters);
// IServiceContainer Register<TService, TImplementation>(params object[] parameters) where TImplementation : TService;
// T Get<T>();
// object Get(Type type);
// /// <summary>
// /// 创建目标类型的对象, 并注入依赖项
// /// </summary>
// object? Instantiate(Type type, params object[] parameters);
// IServiceContainer Build();
// IServiceContainer Run<T>(Action<T> action);
// IServiceContainer Run<T1, T2>(Action<T1, T2> action);
// IServiceContainer Run<T1, T2, T3>(Action<T1, T2, T3> action);
// IServiceContainer Run<T1, T2, T3, T4>(Action<T1, T2, T3, T4> action);
// IServiceContainer Run<T1, T2, T3, T4, T5>(Action<T1, T2, T3, T4, T5> action);
// IServiceContainer Run<T1, T2, T3, T4, T5, T6>(Action<T1, T2, T3, T4, T5, T6> action);
// IServiceContainer Run<T1, T2, T3, T4, T5, T6, T7>(Action<T1, T2, T3, T4, T5, T6, T7> action);
// IServiceContainer Run<T1, T2, T3, T4, T5, T6, T7, T8>(Action<T1, T2, T3, T4, T5, T6, T7, T8> action);
// }
// public class ServiceContainer : IServiceContainer
// {
// private readonly ConcurrentDictionary<string, object> _dependencies;
// private readonly ConcurrentDictionary<string, Type> _typeMappings;
// private readonly List<Type> _waitingForInstantiation;
// public ServiceContainer()
// {
// _dependencies = new ConcurrentDictionary<string, object>
// {
// [typeof(IServiceContainer).FullName] = this
// };
// _typeMappings = new ConcurrentDictionary<string, Type>();
// _waitingForInstantiation = [];
// }
// public object GetOrCreateServiceInstance(Type type, params object[] parameters)
// {
// Register(type);
// object instance;
// if (_dependencies.ContainsKey(type.FullName))
// {
// instance = _dependencies[type.FullName];
// }
// else
// {
// instance = Activator.CreateInstance(type);
// _dependencies[type.FullName] = instance;
// }
// return instance;
// }
// public T CreateServiceInstance<T>(params object[] parameters)
// {
// return (T)GetOrCreateServiceInstance(typeof(T), parameters);
// }
// public IServiceContainer Reset()
// {
// foreach(var instancei in _dependencies.Values)
// {
// if (typeof(IDisposable).IsAssignableFrom(instancei.GetType()) && instancei is IDisposable disposable)
// {
// disposable.Dispose();
// }
// }
// _dependencies.Clear();
// _waitingForInstantiation.Clear();
// //_typeMappings.Clear();
// return this;
// }
// public IServiceContainer Register(Type type, params object[] parameters)
// {
// if (!_typeMappings.ContainsKey(type.FullName))
// {
// _typeMappings[type.FullName] = type;
// }
// return this;
// }
// public IServiceContainer Register<T>(params object[] parameters)
// {
// Register(typeof(T), parameters);
// return this;
// }
// public IServiceContainer Register<TService, TImplementation>(params object[] parameters)
// where TImplementation : TService
// {
// _typeMappings[typeof(TService).FullName!] = typeof(TImplementation);
// return this;
// }
// public object Get(Type type)
// {
// if (!_dependencies.TryGetValue(type.FullName, out object value))
// {
// Register(type);
// value = Instantiate(type);
// InjectDependencies(type);
// }
// return value;
// }
// public T Get<T>()
// {
// if(!_dependencies.TryGetValue(typeof(T).FullName, out object value))
// {
// Register<T>();
// value = Instantiate(typeof(T));
// }
// return (T)value;
// //throw new InvalidOperationException("目标类型未创建实例");
// }
// public IServiceContainer Build()
// {
// foreach (var type in _typeMappings.Values)
// {
// if(!_dependencies.ContainsKey(type.FullName))
// {
// _dependencies[type.FullName] = Activator.CreateInstance(type);
// }
// }
// foreach (var instance in _dependencies.Values)
// {
// InjectDependencies(instance); // 替换占位符
// }
// //var instance = Instantiate(item.Value);
// TryInstantiateWaitingDependencies();
// return this;
// }
// public object? Instantiate(Type controllerType, params object[] parameters)
// {
// var instance = Activator.CreateInstance(controllerType, parameters);
// if(instance != null)
// {
// InjectDependencies(instance);
// }
// return instance;
// }
// private void InjectDependencies(object instance)
// {
// var properties = instance.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public)
// .Where(p => p.CanWrite && p.GetCustomAttribute<AutoInjectionAttribute>() != null);
// foreach (var property in properties)
// {
// var propertyType = property.PropertyType;
// if (_dependencies.TryGetValue(propertyType.FullName, out var dependencyInstance))
// {
// property.SetValue(instance, dependencyInstance);
// }
// }
// }
// private void TryInstantiateWaitingDependencies()
// {
// foreach (var waitingType in _waitingForInstantiation.ToList())
// {
// if (_typeMappings.TryGetValue(waitingType.FullName!, out var implementationType))
// {
// var instance = Instantiate(implementationType);
// if (instance != null)
// {
// _dependencies[waitingType.FullName] = instance;
// _waitingForInstantiation.Remove(waitingType);
// }
// }
// }
// }
// #region run()
// public IServiceContainer Run<T>(Action<T> action)
// {
// var service = Get<T>();
// if (service != null)
// {
// action(service);
// }
// return this;
// }
// public IServiceContainer Run<T1, T2>(Action<T1, T2> action)
// {
// var service1 = Get<T1>();
// var service2 = Get<T2>();
// action(service1, service2);
// return this;
// }
// public IServiceContainer Run<T1, T2, T3>(Action<T1, T2, T3> action)
// {
// var service1 = Get<T1>();
// var service2 = Get<T2>();
// var service3 = Get<T3>();
// action(service1, service2, service3);
// return this;
// }
// public IServiceContainer Run<T1, T2, T3, T4>(Action<T1, T2, T3, T4> action)
// {
// var service1 = Get<T1>();
// var service2 = Get<T2>();
// var service3 = Get<T3>();
// var service4 = Get<T4>();
// action(service1, service2, service3, service4);
// return this;
// }
// public IServiceContainer Run<T1, T2, T3, T4, T5>(Action<T1, T2, T3, T4, T5> action)
// {
// var service1 = Get<T1>();
// var service2 = Get<T2>();
// var service3 = Get<T3>();
// var service4 = Get<T4>();
// var service5 = Get<T5>();
// action(service1, service2, service3, service4, service5);
// return this;
// }
// public IServiceContainer Run<T1, T2, T3, T4, T5, T6>(Action<T1, T2, T3, T4, T5, T6> action)
// {
// var service1 = Get<T1>();
// var service2 = Get<T2>();
// var service3 = Get<T3>();
// var service4 = Get<T4>();
// var service5 = Get<T5>();
// var service6 = Get<T6>();
// action(service1, service2, service3, service4, service5, service6);
// return this;
// }
// public IServiceContainer Run<T1, T2, T3, T4, T5, T6, T7>(Action<T1, T2, T3, T4, T5, T6, T7> action)
// {
// var service1 = Get<T1>();
// var service2 = Get<T2>();
// var service3 = Get<T3>();
// var service4 = Get<T4>();
// var service5 = Get<T5>();
// var service6 = Get<T6>();
// var service7 = Get<T7>();
// action(service1, service2, service3, service4, service5, service6, service7);
// return this;
// }
// public IServiceContainer Run<T1, T2, T3, T4, T5, T6, T7, T8>(Action<T1, T2, T3, T4, T5, T6, T7, T8> action)
// {
// var service1 = Get<T1>();
// var service2 = Get<T2>();
// var service3 = Get<T3>();
// var service4 = Get<T4>();
// var service5 = Get<T5>();
// var service6 = Get<T6>();
// var service7 = Get<T7>();
// var service8 = Get<T8>();
// action(service1, service2, service3, service4, service5, service6, service7, service8);
// return this;
// }
// #endregion
// }
// /* public interface IServiceContainer
// {
// ServiceContainer Register<T>(params object[] parameters);
// ServiceContainer Register<TService, TImplementation>(params object[] parameters) where TImplementation : TService;
// TService Resolve<TService>();
// void Get<T>(Action<T> action);
// object Instantiate(Type type, params object[] parameters);
// }
// public class ServiceContainer : IServiceContainer
// {
// private readonly Dictionary<Type, object> _dependencies;
// public ServiceContainer()
// {
// _dependencies = new Dictionary<Type, object>
// {
// [typeof(IServiceContainer)] = this
// };
// }
// public void Get<T>(Action<T> action)
// {
// var service = Resolve<T>();
// action(service);
// }
// public ServiceContainer Register<T>(params object[] parameters)
// {
// var instance = Instantiate(typeof(T), parameters);
// _dependencies[typeof(T)] = instance;
// return this;
// }
// public ServiceContainer Register<TService, TImplementation>(params object[] parameters)
// where TImplementation : TService
// {
// _dependencies[typeof(TService)] = Instantiate(typeof(TImplementation), parameters);
// return this;
// }
// public TService Resolve<TService>()
// {
// return (TService)_dependencies[typeof(TService)];
// }
// public object Instantiate(Type controllerType, params object[] parameters)
// {
// var constructors = controllerType.GetConstructors(); // 获取控制器的所有构造函数
// // 查找具有最多参数的构造函数
// var constructor = constructors.OrderByDescending(c => c.GetParameters().Length).FirstOrDefault();
// if (constructor != null)
// {
// if (parameters.Length > 0)
// {
// return Activator.CreateInstance(controllerType, parameters);
// }
// else {
// var tmpParameters = constructor.GetParameters();
// var dependencyInstances = new List<object>();
// foreach (var parameter in tmpParameters)
// {
// var parameterType = parameter.ParameterType;
// _dependencies.TryGetValue(parameterType, out var dependencyInstance);
// dependencyInstances.Add(dependencyInstance);
// if (dependencyInstance == null)
// {
// return null;
// }
// }
// // 用解析的依赖项实例化目标类型
// return Activator.CreateInstance(controllerType, dependencyInstances.ToArray());
// }
// }
// else
// {
// return Activator.CreateInstance(controllerType);
// }
// }
// }*/
//}

View File

@@ -0,0 +1,185 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace Serein.Tool
{
public static class DataHelper
{
/// <summary>
/// 把Object转换为Json字符串
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public static string ToJson(this object obj)
{
IsoDateTimeConverter val = new IsoDateTimeConverter();
val.DateTimeFormat = "yyyy-MM-dd HH:mm:ss";
IsoDateTimeConverter val2 = val;
return JsonConvert.SerializeObject(obj, (JsonConverter[])(object)new JsonConverter[1] { (JsonConverter)val2 });
}
/// <summary>
/// 把Json文本转为实体
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="input"></param>
/// <returns></returns>
public static T FromJSON<T>(this string input)
{
try
{
if (typeof(T).IsAssignableFrom(typeof(T)))
{
}
return JsonConvert.DeserializeObject<T>(input);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
// return default(T);
return default;
}
}
public static List<T> IListToList<T>(IList list)
{
T[] array = new T[list.Count];
list.CopyTo(array, 0);
return new List<T>(array);
}
public static DataTable GetNewDataTable(DataTable dt, string condition)
{
if (!IsExistRows(dt))
{
if (condition.Trim() == "")
{
return dt;
}
DataTable dataTable = new DataTable();
dataTable = dt.Clone();
DataRow[] array = dt.Select(condition);
for (int i = 0; i < array.Length; i++)
{
dataTable.ImportRow(array[i]);
}
return dataTable;
}
return null;
}
public static bool IsExistRows(DataTable dt)
{
if (dt != null && dt.Rows.Count > 0)
{
return false;
}
return true;
}
public static Hashtable DataTableToHashtable(DataTable dt)
{
Hashtable hashtable = new Hashtable();
foreach (DataRow row in dt.Rows)
{
for (int i = 0; i < dt.Columns.Count; i++)
{
string columnName = dt.Columns[i].ColumnName;
hashtable[columnName] = row[columnName];
}
}
return hashtable;
}
public static DataTable ListToDataTable<T>(List<T> entitys)
{
if (entitys == null || entitys.Count < 1)
{
return null;
}
Type type = entitys[0].GetType();
PropertyInfo[] properties = type.GetProperties();
DataTable dataTable = new DataTable();
for (int i = 0; i < properties.Length; i++)
{
dataTable.Columns.Add(properties[i].Name);
}
foreach (T entity in entitys)
{
object obj = entity;
if (obj.GetType() != type)
{
throw new Exception("要转换的集合元素类型不一致");
}
object[] array = new object[properties.Length];
for (int j = 0; j < properties.Length; j++)
{
array[j] = properties[j].GetValue(obj, null);
}
dataTable.Rows.Add(array);
}
return dataTable;
}
public static string DataTableToXML(DataTable dt)
{
if (dt != null && dt.Rows.Count > 0)
{
StringWriter stringWriter = new StringWriter();
dt.WriteXml((TextWriter)stringWriter);
return stringWriter.ToString();
}
return string.Empty;
}
public static string DataSetToXML(DataSet ds)
{
if (ds != null)
{
StringWriter stringWriter = new StringWriter();
ds.WriteXml((TextWriter)stringWriter);
return stringWriter.ToString();
}
return string.Empty;
}
}
}