重新设计了FlowLIbrary相关类;为工作台默认添加了基础依赖、默认画布。

This commit is contained in:
fengjiayi
2025-07-28 12:16:29 +08:00
parent 6354c4c7fd
commit ccb8e49abc
39 changed files with 497 additions and 453 deletions

View File

@@ -27,7 +27,7 @@ namespace Serein.FlowStartTool
Console.WriteLine($"{DateTime.Now} [{infoType}] : {value}{Environment.NewLine}"); Console.WriteLine($"{DateTime.Now} [{infoType}] : {value}{Environment.NewLine}");
}; };
await flowEnvironment.StartRemoteServerAsync(7525); // 启动 web socket 监听远程请求 //await flowEnvironment.StartRemoteServerAsync(7525); // 启动 web socket 监听远程请求
IsRuning = false; IsRuning = false;
} }

View File

@@ -179,19 +179,14 @@ namespace Serein.Library.Api
/// </summary> /// </summary>
public class LoadDllEventArgs : FlowEventArgs public class LoadDllEventArgs : FlowEventArgs
{ {
public LoadDllEventArgs(NodeLibraryInfo nodeLibraryInfo, List<MethodDetailsInfo> MethodDetailss) public LoadDllEventArgs(FlowLibraryInfo nodeLibraryInfo)
{ {
this.NodeLibraryInfo = nodeLibraryInfo; this.NodeLibraryInfo = nodeLibraryInfo;
this.MethodDetailss = MethodDetailss;
} }
/// <summary> /// <summary>
/// 已加载了的程序集 /// 已加载了的程序集
/// </summary> /// </summary>
public NodeLibraryInfo NodeLibraryInfo { get;} public FlowLibraryInfo NodeLibraryInfo { get;}
/// <summary>
/// dll文件中有效的流程方法描述
/// </summary>
public List<MethodDetailsInfo> MethodDetailss { get;}
} }
/// <summary> /// <summary>
@@ -791,7 +786,7 @@ namespace Serein.Library.Api
/// <summary> /// <summary>
/// 是否全局中断 /// 是否全局中断
/// </summary> /// </summary>
bool IsGlobalInterrupt { get; } bool _IsGlobalInterrupt { get; }
/// <summary> /// <summary>
/// <para>表示是否正在控制远程</para> /// <para>表示是否正在控制远程</para>

View File

@@ -1,13 +1,10 @@
using Microsoft.CodeAnalysis.CSharp.Syntax; using Serein.Library.Api;
using Serein.Library.Api;
using Serein.Library.Utils; using Serein.Library.Utils;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Xml.Linq;
namespace Serein.Library namespace Serein.Library
{ {

View File

@@ -14,18 +14,21 @@ namespace Serein.Library
/// 基础功能 /// 基础功能
/// </summary> /// </summary>
[DynamicFlow(Name ="[基础功能]")] [DynamicFlow(Name ="[基础功能]")]
public static class SereinBaseFunction public static class FlowBaseLibrary
{ {
[NodeAction(NodeType.Action, "对象透传")] [NodeAction(NodeType.Action, "对象透传")]
public static object SereinTransmissionObject(object value) => value; public static object TransmissionObject(object value) => value;
[NodeAction(NodeType.Action, "键值对组装")] [NodeAction(NodeType.Action, "键值对组装")]
public static Dictionary<string, object> SereinKvDataCollection(string argName, public static Dictionary<string, object> DictSet(string argNames, params object[] value)
params object[] value)
{ {
var names = argName.Split(';'); var names = argNames.Split(';');
var count = Math.Min(value.Length, names.Length); if(value.Length != names.Length)
{
throw new ArgumentException("参数名称数量与入参数量不一致");
}
var count = value.Length;
var dict = new Dictionary<string, object>(); var dict = new Dictionary<string, object>();
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
@@ -35,13 +38,13 @@ namespace Serein.Library
} }
[NodeAction(NodeType.Action, "数组组装")] [NodeAction(NodeType.Action, "数组组装")]
public static object[] SereinListDataCollection(params object[] value) public static object[] ArraySet(params object[] value)
{ {
return value; return value;
} }
[NodeAction(NodeType.Action, "输出")] [NodeAction(NodeType.Action, "输出")]
public static object[] SereinConsole(params object[] value) public static object[] Console(params object[] value)
{ {
foreach (var item in value) foreach (var item in value)
{ {
@@ -51,7 +54,7 @@ namespace Serein.Library
} }
[NodeAction(NodeType.Action, "逻辑分支")] [NodeAction(NodeType.Action, "逻辑分支")]
public static object SereinLogicalBranch([NodeParam(IsExplicit = false)]bool @bool, public static object LogicalBranch([NodeParam(IsExplicit = false)]bool @bool,
object t_value, object t_value,
object f_value) object f_value)
{ {
@@ -59,7 +62,7 @@ namespace Serein.Library
} }
[NodeAction(NodeType.Action, "文本拼接")] [NodeAction(NodeType.Action, "文本拼接")]
public static string SereinTextJoin(params object[] value) public static string TextJoin(params object[] value)
{ {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
foreach (var item in value) foreach (var item in value)
@@ -83,19 +86,19 @@ namespace Serein.Library
[NodeAction(NodeType.Action, "键值对动态构建对象")] [NodeAction(NodeType.Action, "键值对动态构建对象")]
public static object SereinKvDataToObject(Dictionary<string, object> dict, public static object CreateDynamicObjectOfDict(Dictionary<string, object> dict,
string classTypeName = "newClass_dynamic", string classTypeName = "newClass_dynamic",
bool IsPrint = false) bool IsPrint = false)
{ {
if (!DynamicObjectHelper.TryResolve(dict, classTypeName, out var result)) if (!DynamicObjectHelper.TryResolve(dict, classTypeName, out var result))
{ {
Console.WriteLine("赋值过程中有错误,请检查属性名和类型!"); System.Console.WriteLine("赋值过程中有错误,请检查属性名和类型!");
} }
else else
{ {
if (IsPrint) if (IsPrint)
{ {
Console.WriteLine("创建完成,正在打印结果"); System.Console.WriteLine("创建完成,正在打印结果");
DynamicObjectHelper.PrintObjectProperties(result); DynamicObjectHelper.PrintObjectProperties(result);
} }
} }
@@ -104,7 +107,7 @@ namespace Serein.Library
[NodeAction(NodeType.Action, "设置或更新全局数据")] [NodeAction(NodeType.Action, "设置或更新全局数据")]
public static object SereinAddOrUpdateFlowGlobalData(string name, object data) public static object AddOrUpdateFlowGlobalData(string name, object data)
{ {
SereinEnv.AddOrUpdateFlowGlobalData(name, data); SereinEnv.AddOrUpdateFlowGlobalData(name, data);
return data; return data;

View File

@@ -631,7 +631,7 @@ namespace Serein.Library
public string ProjectFileLocation => throw new NotImplementedException(); public string ProjectFileLocation => throw new NotImplementedException();
public bool IsGlobalInterrupt => throw new NotImplementedException(); public bool _IsGlobalInterrupt => throw new NotImplementedException();
public bool IsControlRemoteEnv => throw new NotImplementedException(); public bool IsControlRemoteEnv => throw new NotImplementedException();

View File

@@ -12,13 +12,12 @@ namespace Serein.Library
/// <summary> /// <summary>
/// 环境方法信息 /// 环境方法信息
/// </summary> /// </summary>
public LibraryMds[] LibraryMds { get; set; } public FlowLibraryInfo[] LibraryMds { get; set; }
/// <summary> /// <summary>
/// 项目信息 /// 项目信息
/// </summary> /// </summary>
public SereinProjectData Project { get; set; } public SereinProjectData Project { get; set; }
// IOC节点对象信息
} }
@@ -26,16 +25,27 @@ namespace Serein.Library
/// <summary> /// <summary>
/// 程序集相关的方法信息 /// 程序集相关的方法信息
/// </summary> /// </summary>
public class LibraryMds public class FlowLibraryInfo
{ {
/// <summary> /// <summary>
/// 程序集名称 /// 程序集名称
/// </summary> /// </summary>
public string AssemblyName { get; set; } public string AssemblyName { get; set; }
/// <summary>
/// 文件名
/// </summary>
public string FileName { get; set; }
/// <summary>
/// 路径
/// </summary>
public string FilePath { get; set; }
/// <summary> /// <summary>
/// 相关的方法详情 /// 相关的方法详情
/// </summary> /// </summary>
public MethodDetailsInfo[] Mds { get; set; } public List<MethodDetailsInfo> MethodInfos { get; set; }
} }
@@ -57,7 +67,7 @@ namespace Serein.Library
/// 依赖的DLL /// 依赖的DLL
/// </summary> /// </summary>
public NodeLibraryInfo[] Librarys { get; set; } public FlowLibraryInfo[] Librarys { get; set; }
/// <summary> /// <summary>
/// 画布集合 /// 画布集合
@@ -89,29 +99,16 @@ namespace Serein.Library
} }
/*
/// <summary> /// <summary>
/// 项目依赖的程序集,项目文件相关 /// 项目依赖的程序集,项目文件相关
/// </summary> /// </summary>
/// <summary> /// <summary>
public class NodeLibraryInfo public class FlowLibraryInfo
{ {
/// <summary>
/// 文件名
/// </summary>
public string FileName { get; set; }
/// <summary>
/// 路径
/// </summary>
public string FilePath { get; set; }
/// <summary>
/// 所属的程序集名称
/// </summary>
public string AssemblyName { get; set; }
} }
*/
/// <summary> /// <summary>
/// 节点信息,项目文件相关 /// 节点信息,项目文件相关

View File

@@ -1,4 +1,5 @@
using System; using System;
using System.Text.RegularExpressions;
namespace Serein.Library namespace Serein.Library
{ {
@@ -85,9 +86,9 @@ namespace Serein.Library
public sealed class NodeActionAttribute : Attribute public sealed class NodeActionAttribute : Attribute
{ {
public NodeActionAttribute(NodeType methodDynamicType, public NodeActionAttribute(NodeType methodDynamicType,
string methodTips = "", string methodTips = "",
bool scan = true, bool scan = true,
string lockName = "") string lockName = "")
{ {
Scan = scan; Scan = scan;
MethodDynamicType = methodDynamicType; MethodDynamicType = methodDynamicType;
@@ -110,6 +111,10 @@ namespace Serein.Library
/// 暂无意义 /// 暂无意义
/// </summary> /// </summary>
public string LockName; public string LockName;
/// <summary>
/// 分组名称,暂无意义
/// </summary>
public string GroupName;
} }

View File

@@ -1,16 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<Version>1.2.1.1</Version>
<TargetFrameworks>net8.0;net462</TargetFrameworks>
<BaseOutputPath>..\.\.Output</BaseOutputPath>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<Title>SereinFow</Title> <Title>SereinFow</Title>
<Version>1.2.2</Version>
<Description>动态节点流、可视化编辑的基本依赖支持导入C# DLL生成自定义节点提供二次开发支持适合用于可视化编程和流程设计</Description> <Description>动态节点流、可视化编辑的基本依赖支持导入C# DLL生成自定义节点提供二次开发支持适合用于可视化编程和流程设计</Description>
<PackageReadmeFile>README.md</PackageReadmeFile> <PackageReadmeFile>README.md</PackageReadmeFile>
<RepositoryUrl>https://github.com/fhhyyp/serein-flow</RepositoryUrl> <RepositoryUrl>https://github.com/fhhyyp/serein-flow</RepositoryUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression> <PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance> <PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
<TargetFrameworks>net8.0;net462</TargetFrameworks>
<BaseOutputPath>..\.\.Output</BaseOutputPath>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<LangVersion>latest</LangVersion> <LangVersion>latest</LangVersion>
<SatelliteResourceLanguages>no</SatelliteResourceLanguages> <SatelliteResourceLanguages>no</SatelliteResourceLanguages>
@@ -22,6 +23,22 @@
<CompilerGeneratedFilesOutputPath>.\obj\g</CompilerGeneratedFilesOutputPath> <CompilerGeneratedFilesOutputPath>.\obj\g</CompilerGeneratedFilesOutputPath>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net8.0|AnyCPU'">
<NoWarn>1701;1702;1573</NoWarn>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net462|AnyCPU'">
<NoWarn>1701;1702;1573</NoWarn>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net8.0|AnyCPU'">
<NoWarn>1701;1702;1573</NoWarn>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net462|AnyCPU'">
<NoWarn>1701;1702;1573</NoWarn>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<Compile Remove="Http\**" /> <Compile Remove="Http\**" />
<Compile Remove="Network\**" /> <Compile Remove="Network\**" />
@@ -45,7 +62,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.13.0" />
<PackageReference Include="Microsoft.Extensions.ObjectPool" Version="9.0.0" /> <PackageReference Include="Microsoft.Extensions.ObjectPool" Version="9.0.0" />
<PackageReference Include="System.IO.Ports" Version="9.0.7" /> <PackageReference Include="System.IO.Ports" Version="9.0.7" />
<PackageReference Include="System.Reactive" Version="6.0.1" /> <PackageReference Include="System.Reactive" Version="6.0.1" />

View File

@@ -1,5 +1,4 @@
using Microsoft.CodeAnalysis.CSharp.Syntax; using Serein.Library.Api;
using Serein.Library.Api;
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;

View File

@@ -208,7 +208,7 @@ namespace Serein.NodeFlow.Env
{ {
CanvasInfo = new FlowCanvasDetailsInfo CanvasInfo = new FlowCanvasDetailsInfo
{ {
Name = $"Canvas {_add_canvas_count++}", Name = string.IsNullOrWhiteSpace(canvasName) ? $"Canvas {_add_canvas_count++}" : canvasName,
Width = width, Width = width,
Height = height, Height = height,
Guid = Guid.NewGuid().ToString(), Guid = Guid.NewGuid().ToString(),

View File

@@ -135,7 +135,7 @@ namespace Serein.NodeFlow.Env
public string ProjectFileLocation => currentFlowEnvironment.EnvName; public string ProjectFileLocation => currentFlowEnvironment.EnvName;
/// <inheritdoc/> /// <inheritdoc/>
public bool IsGlobalInterrupt => currentFlowEnvironment.IsGlobalInterrupt; public bool _IsGlobalInterrupt => currentFlowEnvironment._IsGlobalInterrupt;
/// <inheritdoc/> /// <inheritdoc/>
public bool IsControlRemoteEnv => currentFlowEnvironment.IsControlRemoteEnv; public bool IsControlRemoteEnv => currentFlowEnvironment.IsControlRemoteEnv;

View File

@@ -2,6 +2,7 @@
using Serein.Library.Api; using Serein.Library.Api;
using Serein.Library.Utils; using Serein.Library.Utils;
using Serein.Library.Utils.SereinExpression; using Serein.Library.Utils.SereinExpression;
using Serein.NodeFlow.Model.Library;
using Serein.NodeFlow.Services; using Serein.NodeFlow.Services;
using Serein.NodeFlow.Tool; using Serein.NodeFlow.Tool;
using System.Text; using System.Text;
@@ -38,13 +39,13 @@ namespace Serein.NodeFlow.Env
Event = flowEnvironmentEvent; Event = flowEnvironmentEvent;
NodeMVVMManagement = nodeMVVMService; NodeMVVMManagement = nodeMVVMService;
FlowEdit = flowEdit; FlowEdit = flowEdit;
FlowLibraryService = flowLibraryManagement;
IOC = sereinIOC; IOC = sereinIOC;
this.flowModelService = flowModelService;
FlowControl = flowControl; FlowControl = flowControl;
this.flowOperationService = flowOperationService; _flowLibraryService = flowLibraryManagement;
this.IsGlobalInterrupt = false; _flowModelService = flowModelService;
this.flowEnvIOC = sereinIOC; _flowOperationService = flowOperationService;
_IsGlobalInterrupt = false;
_flowEnvIOC = sereinIOC;
} }
@@ -146,7 +147,7 @@ namespace Serein.NodeFlow.Env
/// <summary> /// <summary>
/// 是否全局中断 /// 是否全局中断
/// </summary> /// </summary>
public bool IsGlobalInterrupt { get; set; } public bool _IsGlobalInterrupt { get; set; }
/// <summary> /// <summary>
/// <para>单例模式IOC容器内部维护了一个实例字典默认使用类型的FullName作为Key如果以“接口-实现类”的方式注册那么将使用接口类型的FullName作为Key。</para> /// <para>单例模式IOC容器内部维护了一个实例字典默认使用类型的FullName作为Key如果以“接口-实现类”的方式注册那么将使用接口类型的FullName作为Key。</para>
@@ -185,22 +186,22 @@ namespace Serein.NodeFlow.Env
/// <summary> /// <summary>
/// local环境的IOC容器主要用于注册本地环境的服务 /// local环境的IOC容器主要用于注册本地环境的服务
/// </summary> /// </summary>
private ISereinIOC flowEnvIOC; private ISereinIOC _flowEnvIOC;
/// <summary> /// <summary>
/// 通过程序集名称管理动态加载的程序集用于节点创建提供方法描述流程运行时提供Emit委托 /// 通过程序集名称管理动态加载的程序集用于节点创建提供方法描述流程运行时提供Emit委托
/// </summary> /// </summary>
private readonly FlowLibraryService FlowLibraryService; private readonly FlowLibraryService _flowLibraryService;
/// <summary> /// <summary>
/// 流程节点操作服务 /// 流程节点操作服务
/// </summary> /// </summary>
private readonly FlowOperationService flowOperationService; private readonly FlowOperationService _flowOperationService;
/// <summary> /// <summary>
/// 流程画布、节点实体管理服务 /// 流程画布、节点实体管理服务
/// </summary> /// </summary>
private readonly FlowModelService flowModelService; private readonly FlowModelService _flowModelService;
/* /// <summary> /* /// <summary>
/// 环境加载的节点集合 /// 环境加载的节点集合
@@ -253,7 +254,7 @@ namespace Serein.NodeFlow.Env
public async Task<FlowEnvInfo> GetEnvInfoAsync() public async Task<FlowEnvInfo> GetEnvInfoAsync()
{ {
// 获取所有的程序集对应的方法信息(程序集相关的数据) // 获取所有的程序集对应的方法信息(程序集相关的数据)
var libraryMdss = this.FlowLibraryService.GetAllLibraryMds().ToArray(); var libraryMdss = this._flowLibraryService.GetAllLibraryMds().ToArray();
// 获取当前项目的信息(节点相关的数据) // 获取当前项目的信息(节点相关的数据)
var project = await GetProjectInfoAsync(); // 远程连接获取远程环境项目信息 var project = await GetProjectInfoAsync(); // 远程连接获取远程环境项目信息
SereinEnv.WriteLine(InfoType.INFO, "已将当前环境信息发送到远程客户端"); SereinEnv.WriteLine(InfoType.INFO, "已将当前环境信息发送到远程客户端");
@@ -328,8 +329,6 @@ namespace Serein.NodeFlow.Env
throw; throw;
} }
//
//await SetStartNodeAsync("", projectData.StartNode); // 设置起始节点
}); });
} }
@@ -428,9 +427,9 @@ namespace Serein.NodeFlow.Env
{ {
var projectData = new SereinProjectData() var projectData = new SereinProjectData()
{ {
Librarys = this.FlowLibraryService.GetAllLibraryInfo().ToArray(), Librarys = this._flowLibraryService.GetAllLibraryInfo().ToArray(),
Nodes = flowModelService.GetAllNodeModel().Select(node => node.ToInfo()).Where(info => info is not null).ToArray(), Nodes = _flowModelService.GetAllNodeModel().Select(node => node.ToInfo()).Where(info => info is not null).ToArray(),
Canvass = flowModelService.GetAllCanvasModel().Select(canvas => canvas.ToInfo()).ToArray(), Canvass = _flowModelService.GetAllCanvasModel().Select(canvas => canvas.ToInfo()).ToArray(),
//StartNode = NodeModels.Values.FirstOrDefault(it => it.IsStart)?.Guid, //StartNode = NodeModels.Values.FirstOrDefault(it => it.IsStart)?.Guid,
}; };
@@ -445,24 +444,12 @@ namespace Serein.NodeFlow.Env
/// <returns></returns> /// <returns></returns>
public void LoadLibrary(string dllPath) public void LoadLibrary(string dllPath)
{ {
try try
{ {
#region var libraryInfo = _flowLibraryService.LoadFlowLibrary(dllPath);
var thisAssembly = typeof(IFlowEnvironment).Assembly; if (libraryInfo is not null && libraryInfo.MethodInfos.Count > 0)
var thisAssemblyName = thisAssembly.GetName().Name;
if (!string.IsNullOrEmpty(thisAssemblyName) && FlowLibraryService.GetLibraryMdsOfAssmbly(thisAssemblyName).Count == 0)
{ {
var tmp = FlowLibraryService.LoadLibraryOfPath(thisAssembly.Location); UIContextOperation?.Invoke(() => Event.OnDllLoad(new LoadDllEventArgs(libraryInfo))); // 通知UI创建dll面板显示
UIContextOperation?.Invoke(() => Event.OnDllLoad(new LoadDllEventArgs(tmp.Item1, tmp.Item2))); // 通知UI创建dll面板显示
}
#endregion
(var libraryInfo, var mdInfos) = FlowLibraryService.LoadLibraryOfPath(dllPath);
if (mdInfos.Count > 0)
{
UIContextOperation?.Invoke(() => Event.OnDllLoad(new LoadDllEventArgs(libraryInfo, mdInfos))); // 通知UI创建dll面板显示
} }
} }
catch (Exception ex) catch (Exception ex)
@@ -471,15 +458,15 @@ namespace Serein.NodeFlow.Env
} }
} }
/// <summary> /* /// <summary>
/// 加载本地程序集 /// 加载本地程序集
/// </summary> /// </summary>
/// <param name="flowLibrary"></param> /// <param name="flowLibrary"></param>
public void LoadLibrary(FlowLibrary flowLibrary) public void LoadLibrary(FlowLibraryCache flowLibrary)
{ {
try try
{ {
(var libraryInfo, var mdInfos) = FlowLibraryService.LoadLibraryOfPath(flowLibrary); libraryInfo = FlowLibraryService.LoadFlowLibrary(flowLibrary);
if (mdInfos.Count > 0) if (mdInfos.Count > 0)
{ {
UIContextOperation?.Invoke(() => Event.OnDllLoad(new LoadDllEventArgs(libraryInfo, mdInfos))); // 通知UI创建dll面板显示 UIContextOperation?.Invoke(() => Event.OnDllLoad(new LoadDllEventArgs(libraryInfo, mdInfos))); // 通知UI创建dll面板显示
@@ -490,7 +477,7 @@ namespace Serein.NodeFlow.Env
SereinEnv.WriteLine(InfoType.ERROR, $"无法加载DLL文件{ex.Message}"); SereinEnv.WriteLine(InfoType.ERROR, $"无法加载DLL文件{ex.Message}");
} }
} }*/
/// <summary> /// <summary>
@@ -501,10 +488,10 @@ namespace Serein.NodeFlow.Env
public bool TryUnloadLibrary(string assemblyName) public bool TryUnloadLibrary(string assemblyName)
{ {
// 获取与此程序集相关的节点 // 获取与此程序集相关的节点
var groupedNodes = flowModelService.GetAllNodeModel().Where(node => !string.IsNullOrWhiteSpace(node.MethodDetails.AssemblyName) && node.MethodDetails.AssemblyName.Equals(assemblyName)).ToArray(); var groupedNodes = _flowModelService.GetAllNodeModel().Where(node => !string.IsNullOrWhiteSpace(node.MethodDetails.AssemblyName) && node.MethodDetails.AssemblyName.Equals(assemblyName)).ToArray();
if (groupedNodes.Length == 0) if (groupedNodes.Length == 0)
{ {
var isPass = FlowLibraryService.UnloadLibrary(assemblyName); var isPass = _flowLibraryService.UnloadLibrary(assemblyName);
return isPass; return isPass;
} }
else else
@@ -584,7 +571,7 @@ namespace Serein.NodeFlow.Env
{ {
var model = new FlowCanvasDetails(this); var model = new FlowCanvasDetails(this);
model.LoadInfo(info); model.LoadInfo(info);
flowModelService.AddCanvasModel(model); _flowModelService.AddCanvasModel(model);
if(UIContextOperation is null) if(UIContextOperation is null)
{ {
@@ -608,7 +595,7 @@ namespace Serein.NodeFlow.Env
public bool TryGetMethodDetailsInfo(string assemblyName, string methodName, out MethodDetailsInfo? mdInfo) public bool TryGetMethodDetailsInfo(string assemblyName, string methodName, out MethodDetailsInfo? mdInfo)
{ {
var isPass = FlowLibraryService.TryGetMethodDetails(assemblyName, methodName, out var md); var isPass = _flowLibraryService.TryGetMethodDetails(assemblyName, methodName, out var md);
if (!isPass || md is null) if (!isPass || md is null)
{ {
mdInfo = null; mdInfo = null;
@@ -633,7 +620,7 @@ namespace Serein.NodeFlow.Env
/// <returns></returns> /// <returns></returns>
public bool TryGetDelegateDetails(string assemblyName, string methodName, out DelegateDetails? delegateDetails) public bool TryGetDelegateDetails(string assemblyName, string methodName, out DelegateDetails? delegateDetails)
{ {
return FlowLibraryService.TryGetDelegateDetails(assemblyName, methodName, out delegateDetails); return _flowLibraryService.TryGetDelegateDetails(assemblyName, methodName, out delegateDetails);
} }
/// <summary> /// <summary>
@@ -648,7 +635,7 @@ namespace Serein.NodeFlow.Env
} }
this.UIContextOperation = uiContextOperation; this.UIContextOperation = uiContextOperation;
IOC.Register<UIContextOperation>(() => uiContextOperation).Build(); IOC.Register<UIContextOperation>(() => uiContextOperation).Build();
OnUIContextOperationSet();
} }
@@ -713,9 +700,6 @@ namespace Serein.NodeFlow.Env
} }
/// <summary> /// <summary>
/// 从Guid获取画布 /// 从Guid获取画布
/// </summary> /// </summary>
@@ -729,7 +713,7 @@ namespace Serein.NodeFlow.Env
canvasDetails = null; canvasDetails = null;
return false; return false;
} }
return flowModelService.TryGetCanvasModel(nodeGuid, out canvasDetails); return _flowModelService.TryGetCanvasModel(nodeGuid, out canvasDetails);
} }
@@ -746,7 +730,7 @@ namespace Serein.NodeFlow.Env
nodeModel = null; nodeModel = null;
return false; return false;
} }
return flowModelService.TryGetNodeModel(nodeGuid, out nodeModel); return _flowModelService.TryGetNodeModel(nodeGuid, out nodeModel);
} }
@@ -777,6 +761,20 @@ namespace Serein.NodeFlow.Env
#endregion #endregion
/// <summary>
/// 设置了 UIContextOperation 需要立刻执行的方法,用于加载基础库,创建第一个画布。
/// </summary>
private void OnUIContextOperationSet()
{
var baseLibrary = _flowLibraryService.LoadBaseLibrary();
if (baseLibrary is not null && baseLibrary.MethodInfos.Count > 0)
{
UIContextOperation?.Invoke(() => Event.OnDllLoad(new LoadDllEventArgs(baseLibrary))); // 通知UI创建dll面板显示
}
// 创建第一个画布
FlowEdit.CreateCanvas("Default", 1920, 1080);
}
} }

View File

@@ -97,9 +97,9 @@ namespace Serein.NodeFlow
/// </summary> /// </summary>
/// <param name="libraryInfo"></param> /// <param name="libraryInfo"></param>
/// <returns></returns> /// <returns></returns>
public static NodeLibraryInfo ToLibrary(this NodeLibraryInfo libraryInfo) public static FlowLibraryInfo ToLibrary(this FlowLibraryInfo libraryInfo)
{ {
return new NodeLibraryInfo return new FlowLibraryInfo
{ {
AssemblyName = libraryInfo.AssemblyName, AssemblyName = libraryInfo.AssemblyName,
FileName = libraryInfo.FileName, FileName = libraryInfo.FileName,

View File

@@ -12,52 +12,52 @@ using System.Reflection;
using System.Text; using System.Text;
using static System.Runtime.InteropServices.JavaScript.JSType; using static System.Runtime.InteropServices.JavaScript.JSType;
namespace Serein.NodeFlow namespace Serein.NodeFlow.Model.Library
{ {
public class LibraryMdDd
{
public MethodDetails MethodDetails { get; }
public MethodInfo MethodInfo { get; }
public DelegateDetails DelegateDetails { get; }
public LibraryMdDd(MethodInfo methodInfo, MethodDetails methodDetails, DelegateDetails delegateDetails)
{
MethodDetails = methodDetails;
MethodInfo = methodInfo;
DelegateDetails = delegateDetails;
}
}
/// <summary> /// <summary>
/// 加载在流程中的程序集依赖 /// 加载在流程中的程序集依赖
/// </summary> /// </summary>
public class FlowLibrary public class FlowLibraryCache
{ {
public Assembly Assembly { get; private set; } /// <summary>
/// 通过程序集创建一个流程库实例
//private readonly Action actionOfUnloadAssmbly; /// </summary>
/*, Action actionOfUnloadAssmbly*/ /// <param name="assembly"></param>
//this.actionOfUnloadAssmbly = actionOfUnloadAssmbly; public FlowLibraryCache(Assembly assembly)
public FlowLibrary(Assembly assembly)
{ {
this.Assembly = assembly; Assembly = assembly;
this.FullName = Path.GetFileName(Assembly.Location); FullName = Path.GetFileName(Assembly.Location);
FilePath = Assembly.Location;
this.FilePath = Assembly.Location;
} }
public FlowLibrary(Assembly assembly, /// <summary>
/// 通过动态程序集和文件路径创建一个流程库实例
/// </summary>
/// <param name="dynamicAssembly"></param>
/// <param name="filePath"></param>
public FlowLibraryCache(Assembly dynamicAssembly,
string filePath) string filePath)
{ {
this.Assembly = assembly; Assembly = dynamicAssembly;
this.FullName = Path.GetFileName(filePath); ; FullName = Path.GetFileName(filePath); ;
this.FilePath = filePath; FilePath = filePath;
} }
/// <summary>
/// 程序集本身
/// </summary>
public Assembly Assembly { get; private set; }
/// <summary>
/// 程序集全名
/// </summary>
public string FullName { get; private set; } public string FullName { get; private set; }
/// <summary>
/// 程序集文件路径
/// </summary>
public string FilePath { get; private set; } public string FilePath { get; private set; }
/// <summary> /// <summary>
@@ -65,60 +65,33 @@ namespace Serein.NodeFlow
/// Key 方法名称 /// Key 方法名称
/// Value :方法详情 /// Value :方法详情
/// </summary> /// </summary>
public ConcurrentDictionary<string, MethodDetails> MethodDetailss { get; } = new ConcurrentDictionary<string, MethodDetails>(); public Dictionary<string, MethodDetails> MethodDetailss { get; } = new Dictionary<string, MethodDetails>();
public ConcurrentDictionary<string, MethodInfo> MethodInfos { get; } = new ConcurrentDictionary<string, MethodInfo>();
/// <summary> /// <summary>
/// 管理通过Emit动态构建的委托 /// 加载程序集时创建的方法信息
/// Key :方法名称
/// Value :方法详情
/// </summary> /// </summary>
public ConcurrentDictionary<string, DelegateDetails> DelegateDetailss { get; } = new ConcurrentDictionary<string, DelegateDetails>(); public Dictionary<string, MethodInfo> MethodInfos { get; } = new Dictionary<string, MethodInfo>();
/// <summary> /// <summary>
/// 记录不同的注册时机需要自动创建全局唯一实例的类型信息 /// <para>缓存节点方法通Emit委托</para>
/// <para>Key :方法名称</para>
/// <para>Value :方法详情</para>
/// </summary> /// </summary>
public ConcurrentDictionary<RegisterSequence, List<Type>> RegisterTypes { get; } = new ConcurrentDictionary<RegisterSequence, List<Type>>(); public Dictionary<string, DelegateDetails> DelegateDetailss { get; } = new Dictionary<string, DelegateDetails>();
/// <summary> /// <summary>
/// 卸载当前程序集以及附带的所有信息 /// 用于流程启动时,在不同阶段(Init_Loading_Loaded)需要创建实例的类型信息
/// </summary> /// </summary>
public void Upload() public Dictionary<RegisterSequence, List<Type>> RegisterTypes { get; } = new Dictionary<RegisterSequence, List<Type>>();
{
DelegateDetailss.Clear();
RegisterTypes.Clear();
MethodDetailss.Clear();
//actionOfUnloadAssmbly?.Invoke();
}
/// <summary>
/// 转为依赖信息
/// </summary>
/// <returns></returns>
public NodeLibraryInfo ToInfo()
{
var assemblyName = Assembly.GetName().Name;
return new NodeLibraryInfo
{
AssemblyName = assemblyName,
FileName = this.FullName,
FilePath = this.FilePath,
};
}
/// <summary> /// <summary>
/// 动态加载程序集 /// 动态加载程序集
/// </summary> /// </summary>
/// <param name="assembly">程序集本身</param>
/// <returns></returns> /// <returns></returns>
public bool LoadAssembly() public bool LoadFlowMethod()
{ {
Assembly assembly = this.Assembly; Assembly assembly = Assembly;
#region #region
@@ -132,7 +105,7 @@ namespace Serein.NodeFlow
try try
{ {
types = assembly.GetTypes().ToList(); // 获取程序集中的所有类型 types = assembly.GetTypes().ToList(); // 获取程序集中的所有类型
if (types.Count < 0) // 防止动态程序集中没有类型信息? if (types.Count <= 0)
{ {
return false; return false;
} }
@@ -143,7 +116,7 @@ namespace Serein.NodeFlow
var loaderExceptions = ex.LoaderExceptions; var loaderExceptions = ex.LoaderExceptions;
foreach (var loaderException in loaderExceptions) foreach (var loaderException in loaderExceptions)
{ {
SereinEnv.WriteLine(InfoType.ERROR, loaderException?.Message); SereinEnv.WriteLine(InfoType.ERROR, "加载失败 : " + loaderException?.Message);
} }
return false; return false;
} }
@@ -160,8 +133,7 @@ namespace Serein.NodeFlow
// Type 具有 DynamicFlowAttribute 标记的类型 // Type 具有 DynamicFlowAttribute 标记的类型
// string 类型元数据 DynamicFlowAttribute 特性中的 Name 属性 // string 类型元数据 DynamicFlowAttribute 特性中的 Name 属性
types = types.Where(type => type.GetCustomAttribute<DynamicFlowAttribute>() is DynamicFlowAttribute dynamicFlowAttribute types = types.Where(type => type.GetCustomAttribute<DynamicFlowAttribute>() is DynamicFlowAttribute df && df.Scan).ToList();
&& dynamicFlowAttribute.Scan).ToList();
foreach (var type in types) foreach (var type in types)
{ {
@@ -208,20 +180,16 @@ namespace Serein.NodeFlow
{ {
return false; return false;
} }
// 简单排序一下
//detailss = detailss.OrderBy(k => k.MethodDetails.MethodName,).ToList();
// 简单排序一下
detailss.Sort((a, b) => string.Compare(a.MethodDetails.MethodName, b.MethodDetails.MethodName, StringComparison.OrdinalIgnoreCase)); detailss.Sort((a, b) => string.Compare(a.MethodDetails.MethodName, b.MethodDetails.MethodName, StringComparison.OrdinalIgnoreCase));
foreach (var item in detailss) foreach (var item in detailss)
{ {
SereinEnv.WriteLine(InfoType.INFO, "loading method : " + item.MethodDetails.MethodName); SereinEnv.WriteLine(InfoType.INFO, "加载方法 : " + item.MethodDetails.MethodName);
} }
//detailss.Sort((a, b) => string.Compare());
#region #region
foreach (var item in detailss) foreach (var item in detailss)
{ {
@@ -253,6 +221,36 @@ namespace Serein.NodeFlow
} }
/// <summary>
/// 卸载当前程序集以及附带的所有信息
/// </summary>
public void Unload()
{
DelegateDetailss.Clear();
MethodInfos.Clear();
RegisterTypes.Clear();
MethodDetailss.Clear();
}
/// <summary>
/// 转为依赖信息
/// </summary>
/// <returns></returns>
public FlowLibraryInfo ToInfo()
{
var assemblyName = Assembly.GetName().Name;
var mdInfos = MethodDetailss.Values.Select(x => x.ToInfo()).ToList();
mdInfos.Sort((a, b) => string.Compare(a.MethodName, b.MethodName, StringComparison.OrdinalIgnoreCase));
return new FlowLibraryInfo
{
AssemblyName = assemblyName,
FileName = FullName,
FilePath = FilePath,
MethodInfos = mdInfos.ToList(),
};
}
} }
} }

View File

@@ -0,0 +1,20 @@
using Serein.Library;
using System.Reflection;
namespace Serein.NodeFlow.Model.Library
{
public class LibraryMdDd
{
public MethodDetails MethodDetails { get; }
public MethodInfo MethodInfo { get; }
public DelegateDetails DelegateDetails { get; }
public LibraryMdDd(MethodInfo methodInfo, MethodDetails methodDetails, DelegateDetails delegateDetails)
{
MethodDetails = methodDetails;
MethodInfo = methodInfo;
DelegateDetails = delegateDetails;
}
}
}

View File

@@ -231,7 +231,7 @@ namespace Serein.NodeFlow.Model
var returnType = sereinScript.ParserScript(Script, argTypes); // 开始解析获取程序主节点 var returnType = sereinScript.ParserScript(Script, argTypes); // 开始解析获取程序主节点
MethodDetails.ReturnType = returnType; MethodDetails.ReturnType = returnType;
var scriptMethodInfo = sereinScript.ConvertCSharpCode(methodName, argTypes); var scriptMethodInfo = sereinScript.ConvertCSharpCode(methodName, argTypes);
return scriptMethodInfo; return scriptMethodInfo;
} }
catch (Exception ex) catch (Exception ex)

View File

@@ -42,18 +42,18 @@ namespace Serein.NodeFlow.Model.Operation
{ {
if (!flowModelService.ContainsCanvasModel(CanvasGuid)) if (!flowModelService.ContainsCanvasModel(CanvasGuid))
{ {
flowEnvironment.WriteLine(Library.InfoType.INFO, $"节点取出失败,目标画布不存在[{NodeGuid}]"); flowEnvironment.WriteLine(Serein.Library.InfoType.WARN, $"节点取出失败,目标画布不存在[{NodeGuid}]");
return false; return false;
} }
// 获取目标节点与容器节点 // 获取目标节点与容器节点
if (!flowModelService.TryGetNodeModel(NodeGuid, out var nodeModel)) if (!flowModelService.TryGetNodeModel(NodeGuid, out var nodeModel))
{ {
flowEnvironment.WriteLine(Library.InfoType.INFO, $"节点取出失败,目标节点不存在[{NodeGuid}]"); flowEnvironment.WriteLine(Serein.Library.InfoType.WARN, $"节点取出失败,目标节点不存在[{NodeGuid}]");
return false; return false;
} }
if (nodeModel.ContainerNode is not INodeContainer containerNode) if (nodeModel.ContainerNode is not INodeContainer containerNode)
{ {
flowEnvironment.WriteLine(Library.InfoType.INFO, $"节点取出失败,节点并非容器节点[{nodeModel.Guid}]"); flowEnvironment.WriteLine(Serein.Library.InfoType.WARN, $"节点取出失败,节点并非容器节点[{nodeModel.Guid}]");
return false; return false;
} }
Node = nodeModel; Node = nodeModel;

View File

@@ -97,7 +97,7 @@ namespace Serein.NodeFlow.Model.Operation
// 节点与画布互相绑定 // 节点与画布互相绑定
nodeModel.CanvasDetails = flowCanvasDetails; nodeModel.CanvasDetails = flowCanvasDetails;
flowCanvasDetails.Nodes.Add(nodeModel); flowCanvasDetails.Nodes = [..flowCanvasDetails.Nodes, nodeModel];
flowModelService.AddNodeModel(nodeModel); flowModelService.AddNodeModel(nodeModel);
this.flowNode = nodeModel; this.flowNode = nodeModel;

View File

@@ -1,15 +1,5 @@
using Microsoft.CodeAnalysis.CSharp.Syntax; using Serein.Library;
using Serein.Library;
using Serein.Library.Api; using Serein.Library.Api;
using Serein.Script.Node;
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Linq;
using System.Reflection.Metadata;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace Serein.NodeFlow.Model.Operation namespace Serein.NodeFlow.Model.Operation
{ {

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<Version>1.2.1</Version> <Version>1.2.2</Version>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
@@ -52,6 +52,7 @@
<Compile Remove="Tool\Attribute.cs" /> <Compile Remove="Tool\Attribute.cs" />
<Compile Remove="Tool\DynamicTool.cs" /> <Compile Remove="Tool\DynamicTool.cs" />
<Compile Remove="Tool\ExpressionHelper.cs" /> <Compile Remove="Tool\ExpressionHelper.cs" />
<Compile Remove="Tool\FlowLibraryAssemblyContext2.cs" />
<Compile Remove="Tool\NodeModelBaseFunc.cs" /> <Compile Remove="Tool\NodeModelBaseFunc.cs" />
<Compile Remove="Tool\TcsSignal.cs" /> <Compile Remove="Tool\TcsSignal.cs" />
<Compile Remove="Tool\ToCSharpCodeHelper.cs" /> <Compile Remove="Tool\ToCSharpCodeHelper.cs" />
@@ -69,6 +70,8 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.Common" Version="4.13.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.13.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.6" /> <PackageReference Include="Microsoft.Extensions.Http" Version="9.0.6" />
</ItemGroup> </ItemGroup>

View File

@@ -2,13 +2,14 @@
using Serein.Library.Api; using Serein.Library.Api;
using Serein.Library.FlowNode; using Serein.Library.FlowNode;
using Serein.Library.Utils; using Serein.Library.Utils;
using Serein.NodeFlow.Model.Library;
using Serein.NodeFlow.Tool;
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Runtime.Loader;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Xml.Linq; using System.Xml.Linq;
@@ -28,54 +29,95 @@ namespace Serein.NodeFlow.Services
private readonly IFlowEnvironment flowEnvironment; private readonly IFlowEnvironment flowEnvironment;
/// <summary> /// <summary>
/// 缓存所有加载了的程序集 /// 缓存流程依赖
/// </summary> /// </summary>
private readonly ConcurrentDictionary<string, FlowLibrary> _myFlowLibrarys = new ConcurrentDictionary<string, FlowLibrary>(); private readonly ConcurrentDictionary<string, FlowLibraryCache> _flowLibraryCaches = new ConcurrentDictionary<string, FlowLibraryCache>();
private readonly ConcurrentDictionary<string, FlowLibraryAssemblyContext> _flowLibraryAssemblyContexts
= new ConcurrentDictionary<string, FlowLibraryAssemblyContext>();
/// <summary> /// <summary>
/// 加载类库 /// 每个类库下面至少需要有“Serein.Library.dll”类库依赖
/// </summary> /// </summary>
/// <param name="libraryfilePath"></param> /// <param name="libraryfilePath"></param>
/// <returns></returns> /// <returns></returns>
public (NodeLibraryInfo, List<MethodDetailsInfo>) LoadLibraryOfPath(string libraryfilePath) private bool CheckBaseLibrary(string libraryfilePath, out string baseLibraryPath)
{ {
var dir = Path.GetDirectoryName(libraryfilePath); // 获取目录路径 var dir = Path.GetDirectoryName(libraryfilePath); // 获取目录路径
var sereinFlowBaseLibraryPath = Path.Combine(dir, SereinBaseLibrary);// 每个类库下面至少需要有“Serein.Library.dll”类库依赖 var sereinFlowBaseLibraryPath = Path.Combine(dir, SereinBaseLibrary);
if (!Path.Exists(sereinFlowBaseLibraryPath)) if (!Path.Exists(sereinFlowBaseLibraryPath))
{ {
throw new Exception($"从文件加载DLL失败目标文件夹不存在{SereinBaseLibrary}文件" ); baseLibraryPath = string.Empty;
} return false;
var flowAlc = new FlowLibraryAssemblyContext(sereinFlowBaseLibraryPath, Path.GetFileName(libraryfilePath));
var assembly = flowAlc.LoadFromAssemblyPath(libraryfilePath); // 加载指定路径的程序集
var flowLibrary = new FlowLibrary(assembly);
try
{
var reulst = LoadFlowLibrary(flowLibrary);
return reulst;
}
catch (Exception)
{
flowAlc?.Unload(); // 卸载程序集
flowAlc = null;
GC.Collect(); // 强制触发GC确保卸载成功
GC.WaitForPendingFinalizers();
throw;
} }
baseLibraryPath = sereinFlowBaseLibraryPath;
return true;
} }
/// <summary> /// <summary>
/// 加载类库 /// 加载基础依赖
/// </summary> /// </summary>
/// <param name="flowLibrary"></param> public FlowLibraryInfo LoadBaseLibrary()
/// <returns></returns>
public (NodeLibraryInfo, List<MethodDetailsInfo>) LoadLibraryOfPath(FlowLibrary flowLibrary)
{ {
return LoadFlowLibrary(flowLibrary); Assembly baseAssmbly = typeof(FlowBaseLibrary).Assembly;
var flowLibrary = new FlowLibraryCache(baseAssmbly);
flowLibrary.LoadFlowMethod();
var assemblyName = baseAssmbly.GetName().Name;
if (string.IsNullOrEmpty(assemblyName))
{
throw new Exception($"程序集\"{baseAssmbly}\"返回 Name 为 null");
}
_flowLibraryCaches.TryAdd(assemblyName, flowLibrary);
return flowLibrary.ToInfo();
} }
/// <summary>
/// 加载流程依赖
/// </summary>
/// <param name="libraryfilePath"></param>
/// <exception cref="Exception"></exception>
public FlowLibraryInfo? LoadFlowLibrary(string libraryfilePath)
{
if (!CheckBaseLibrary(libraryfilePath, out var baseLibraryPath))
{
throw new Exception($"从文件加载DLL失败目标文件夹不存在{SereinBaseLibrary}文件");
}
FlowLibraryAssemblyContext flowAlc = new FlowLibraryAssemblyContext(baseLibraryPath, Path.GetFileName(libraryfilePath));
var flowAssembly = flowAlc.LoadFromAssemblyPath(libraryfilePath);
if(flowAssembly is null)
{
throw new Exception($"从文件加载DLL失败FlowLibraryAssemblyContext 加载的程序集为 null \"{libraryfilePath}\"");
}
var flowLibrary = new FlowLibraryCache(flowAssembly);
var isSuccess = flowLibrary.LoadFlowMethod();
if (!isSuccess)
{
flowAlc?.Unload(); // 卸载程序集
GC.Collect(); // 强制触发GC确保卸载成功
GC.WaitForPendingFinalizers();
return null;
}
else
{
var assemblyName = flowAssembly.GetName().Name;
if (string.IsNullOrEmpty(assemblyName))
{
flowLibrary.Unload();
flowAlc?.Unload(); // 卸载程序集
GC.Collect(); // 强制触发GC确保卸载成功
GC.WaitForPendingFinalizers();
return null;
throw new Exception($"程序集\"{flowAssembly}\"返回 Name 为 null");
}
_flowLibraryCaches.TryAdd(assemblyName, flowLibrary);
return flowLibrary.ToInfo();
}
}
/// <summary> /// <summary>
/// 卸载类库 /// 卸载类库
/// </summary> /// </summary>
@@ -83,11 +125,11 @@ namespace Serein.NodeFlow.Services
/// <returns></returns> /// <returns></returns>
public bool UnloadLibrary(string assemblyName) public bool UnloadLibrary(string assemblyName)
{ {
if (_myFlowLibrarys.Remove(assemblyName, out var flowLibrary)) if (_flowLibraryCaches.Remove(assemblyName, out var flowLibrary))
{ {
try try
{ {
flowLibrary.Upload(); // 尝试卸载 flowLibrary.Unload(); // 尝试卸载
flowLibrary = null; flowLibrary = null;
return true; return true;
} }
@@ -104,6 +146,8 @@ namespace Serein.NodeFlow.Services
} }
} }
#region
/// <summary> /// <summary>
/// 获取方法描述 /// 获取方法描述
/// </summary> /// </summary>
@@ -118,7 +162,7 @@ namespace Serein.NodeFlow.Services
methodInfo = null; methodInfo = null;
return false; return false;
} }
if (_myFlowLibrarys.TryGetValue(assemblyName, out var flowLibrary) if (_flowLibraryCaches.TryGetValue(assemblyName, out var flowLibrary)
&& flowLibrary.MethodInfos.TryGetValue(methodName, out methodInfo)) && flowLibrary.MethodInfos.TryGetValue(methodName, out methodInfo))
{ {
return true; return true;
@@ -130,7 +174,7 @@ namespace Serein.NodeFlow.Services
} }
} }
/// <summary> /// <summary>
/// 获取方法描述 /// 获取方法描述
/// </summary> /// </summary>
/// <param name="assemblyName">程序集名称</param> /// <param name="assemblyName">程序集名称</param>
@@ -139,7 +183,7 @@ namespace Serein.NodeFlow.Services
/// <returns>是否获取成功</returns> /// <returns>是否获取成功</returns>
public bool TryGetMethodDetails(string assemblyName, string methodName, [MaybeNullWhen(false)] out MethodDetails md) public bool TryGetMethodDetails(string assemblyName, string methodName, [MaybeNullWhen(false)] out MethodDetails md)
{ {
if (_myFlowLibrarys.TryGetValue(assemblyName, out var flowLibrary) if (_flowLibraryCaches.TryGetValue(assemblyName, out var flowLibrary)
&& flowLibrary.MethodDetailss.TryGetValue(methodName, out md)) && flowLibrary.MethodDetailss.TryGetValue(methodName, out md))
{ {
return true; return true;
@@ -160,7 +204,7 @@ namespace Serein.NodeFlow.Services
/// <returns>是否获取成功</returns> /// <returns>是否获取成功</returns>
public bool TryGetDelegateDetails(string assemblyName, string methodName, [MaybeNullWhen(false)] out DelegateDetails dd) public bool TryGetDelegateDetails(string assemblyName, string methodName, [MaybeNullWhen(false)] out DelegateDetails dd)
{ {
if (_myFlowLibrarys.TryGetValue(assemblyName, out var flowLibrary) if (_flowLibraryCaches.TryGetValue(assemblyName, out var flowLibrary)
&& flowLibrary.DelegateDetailss.TryGetValue(methodName, out dd)) && flowLibrary.DelegateDetailss.TryGetValue(methodName, out dd))
{ {
return true; return true;
@@ -182,7 +226,7 @@ namespace Serein.NodeFlow.Services
{ {
List<MethodDetails> mds = []; List<MethodDetails> mds = [];
foreach (var library in _myFlowLibrarys.Values) foreach (var library in _flowLibraryCaches.Values)
{ {
var t_mds = library.MethodDetailss.Values.Where(it => it.MethodDynamicType == nodeType).ToList(); var t_mds = library.MethodDetailss.Values.Where(it => it.MethodDynamicType == nodeType).ToList();
mds.AddRange(t_mds); mds.AddRange(t_mds);
@@ -197,7 +241,7 @@ namespace Serein.NodeFlow.Services
public Dictionary<RegisterSequence, List<Type>> GetaAutoRegisterType() public Dictionary<RegisterSequence, List<Type>> GetaAutoRegisterType()
{ {
Dictionary<RegisterSequence, List<Type>> rsTypes = new Dictionary<RegisterSequence, List<Type>>(); Dictionary<RegisterSequence, List<Type>> rsTypes = new Dictionary<RegisterSequence, List<Type>>();
foreach (var library in _myFlowLibrarys.Values) foreach (var library in _flowLibraryCaches.Values)
{ {
foreach (var kv in library.RegisterTypes) foreach (var kv in library.RegisterTypes)
{ {
@@ -220,28 +264,26 @@ namespace Serein.NodeFlow.Services
/// <returns></returns> /// <returns></returns>
public List<MethodDetails> GetLibraryMdsOfAssmbly(string assemblyName) public List<MethodDetails> GetLibraryMdsOfAssmbly(string assemblyName)
{ {
if (_myFlowLibrarys.TryGetValue(assemblyName, out var flowLibrary)) if (_flowLibraryCaches.TryGetValue(assemblyName, out var flowLibrary))
{ {
return flowLibrary.MethodDetailss.Values.ToList(); return flowLibrary.MethodDetailss.Values.ToList();
} }
return []; return [];
} }
/// <summary> /// <summary>
/// 获取所有方法信息,用于保存项目时调用 /// 获取流程方法信息,用于保存项目时调用
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public List<LibraryMds> GetAllLibraryMds() public List<FlowLibraryInfo> GetAllLibraryMds()
{ {
List<LibraryMds> mds = new List<LibraryMds>(); List<FlowLibraryInfo> mds = new List<FlowLibraryInfo>();
foreach (FlowLibrary library in _myFlowLibrarys.Values) foreach (FlowLibraryCache library in _flowLibraryCaches.Values)
{ {
var tmp = new LibraryMds var tmp = new FlowLibraryInfo
{ {
AssemblyName = library.FullName, AssemblyName = library.FullName,
Mds = library.MethodDetailss.Values.Select(md => md.ToInfo()).ToArray() MethodInfos = library.MethodDetailss.Values.Select(md => md.ToInfo()).ToList()
}; };
mds.Add(tmp); mds.Add(tmp);
} }
@@ -253,11 +295,11 @@ namespace Serein.NodeFlow.Services
/// 序列化当前项目的依赖信息、节点信息,用于远程登录的场景,需要将依赖信息从本地(受控端)发送到远程(主控端) /// 序列化当前项目的依赖信息、节点信息,用于远程登录的场景,需要将依赖信息从本地(受控端)发送到远程(主控端)
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public List<NodeLibraryInfo> GetAllLibraryInfo() public List<FlowLibraryInfo> GetAllLibraryInfo()
{ {
return _myFlowLibrarys.Values.Select(library => library.ToInfo()).ToList(); return _flowLibraryCaches.Values.Select(library => library.ToInfo()).ToList();
} }
#endregion
#region #region
@@ -266,132 +308,7 @@ namespace Serein.NodeFlow.Services
/// </summary> /// </summary>
public readonly static string SereinBaseLibrary = $"{nameof(Serein)}.{nameof(Library)}.dll"; public readonly static string SereinBaseLibrary = $"{nameof(Serein)}.{nameof(Library)}.dll";
//private (NodeLibraryInfo, List<MethodDetailsInfo>) LoadDllNodeInfo(Assembly assembly)
//{
// if (assembly.FullName?.ToString().Equals(typeof(IFlowEnvironment).Assembly.FullName?.ToString()) == true)
// {
// // 加载基础依赖
// return LoadAssembly(typeof(IFlowEnvironment).Assembly);
// }
// else
// {
// try
// {
// var assembly_result = LoadAssembly(assembly);
// return assembly_result;
// }
// catch (Exception)
// {
// return (null,[]);
// }
// }
//}
private (NodeLibraryInfo, List<MethodDetailsInfo>) LoadFlowLibrary(FlowLibrary flowLibrary)
{
var assembly = flowLibrary.Assembly;
if (assembly.FullName?.ToString().Equals(typeof(IFlowEnvironment).Assembly.FullName?.ToString()) == true)
{
// 加载基础依赖
flowLibrary = new FlowLibrary(typeof(IFlowEnvironment).Assembly);
}
var assmblyName = assembly.GetName().Name;
if (!string.IsNullOrEmpty(assmblyName) && _myFlowLibrarys.ContainsKey(assmblyName))
{
throw new Exception($"程序集[{assembly.GetName().FullName}]已经加载过!");
}
var loadResult = flowLibrary.LoadAssembly(); // 加载程序集
if (loadResult)
{
var assemblyName = assembly.GetName().Name;
if (string.IsNullOrEmpty(assemblyName))
{
throw new Exception($"程序集[{assembly.GetName().FullName}]加载失败,没有程序集名称");
}
_myFlowLibrarys.TryAdd(assemblyName, flowLibrary);
List<MethodDetailsInfo> mdInfos = flowLibrary.MethodDetailss.Values.Select(md => md.ToInfo()).ToList();
mdInfos.Sort((a, b) => string.Compare(a.MethodName, b.MethodName, StringComparison.OrdinalIgnoreCase));
(NodeLibraryInfo, List<MethodDetailsInfo>) result = (flowLibrary.ToInfo(), mdInfos);
return result;
}
else
{
throw new Exception($"程序集[{assembly.GetName().FullName}]加载失败");
}
}
#endregion #endregion
} }
/// <summary>
/// 流程依赖加载
/// </summary>
public class FlowLibraryAssemblyContext : AssemblyLoadContext
{
private readonly AssemblyDependencyResolver _resolver;
/// <summary>
/// 创建新的加载上下文
/// </summary>
/// <param name="sereinFlowLibraryPath">类库路径</param>
/// <param name="name"></param>
public FlowLibraryAssemblyContext(string sereinFlowLibraryPath, string name) : base(name, isCollectible: true)
{
_resolver = new AssemblyDependencyResolver(sereinFlowLibraryPath);
}
protected override Assembly? Load(AssemblyName assemblyName)
{
string? assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName);
if (!string.IsNullOrEmpty(assemblyPath))
{
var assembly = Default.LoadFromAssemblyPath(assemblyPath);
//var assembly = LoadFromAssemblyPath(assemblyPath);
return assembly;
}
else
{
return Default.Assemblies.FirstOrDefault(x => x.FullName == assemblyName.FullName);
}
// return null;
// 构建依赖项的路径
//string assemblyPath = Path.Combine(AppContext.BaseDirectory, assemblyName.Name + ".dll");
//if (File.Exists(assemblyPath))
//{
// return LoadFromAssemblyPath(assemblyPath);
//}
//assemblyPath = Path.Combine(filePath, assemblyName.Name + ".dll");
//if (File.Exists(assemblyPath))
//{
// return LoadFromAssemblyPath(assemblyPath);
//}
//return null; // 如果没有找到,返回 null
}
}
//public static class PluginAssemblyContextExtensions
//{
// public static Assembly FromAssemblyPath(this AssemblyLoadContext context, string path)
// {
// return context.LoadFromAssemblyPath(path);
// }
//}
} }

View File

@@ -1,13 +1,7 @@
using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Emit; using Microsoft.CodeAnalysis.Emit;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace Serein.NodeFlow.Tool namespace Serein.NodeFlow.Tool
{ {

View File

@@ -0,0 +1,59 @@
using System.Reflection;
using System.Runtime.Loader;
namespace Serein.NodeFlow.Tool
{
/// <summary>
/// 流程依赖加载
/// </summary>
public class FlowLibraryAssemblyContext : AssemblyLoadContext
{
private readonly AssemblyDependencyResolver _resolver;
/// <summary>
/// 创建新的加载上下文
/// </summary>
/// <param name="baseLibraryPath">流程基础依赖类库路径</param>
/// <param name="name"></param>
public FlowLibraryAssemblyContext(string baseLibraryPath, string name) : base(name, isCollectible: true)
{
_resolver = new AssemblyDependencyResolver(baseLibraryPath);
}
/// <summary>
/// 加载指定的程序集
/// </summary>
/// <param name="assemblyName"></param>
/// <returns></returns>
protected override Assembly? Load(AssemblyName assemblyName)
{
string? assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName); // 加载程序集
if (!string.IsNullOrEmpty(assemblyPath))
{
var assembly = Default.LoadFromAssemblyPath(assemblyPath); // 通过默认方式进行加载程序集及相关依赖
//var assembly = LoadFromAssemblyPath(assemblyPath);
return assembly;
}
else
{
return Default.Assemblies.FirstOrDefault(x => x.FullName == assemblyName.FullName);
}
// return null;
// 构建依赖项的路径
//string assemblyPath = Path.Combine(AppContext.BaseDirectory, assemblyName.Name + ".dll");
//if (File.Exists(assemblyPath))
//{
// return LoadFromAssemblyPath(assemblyPath);
//}
//assemblyPath = Path.Combine(filePath, assemblyName.Name + ".dll");
//if (File.Exists(assemblyPath))
//{
// return LoadFromAssemblyPath(assemblyPath);
//}
//return null; // 如果没有找到,返回 null
}
}
}

View File

@@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
using System.Text;
using System.Threading.Tasks;
namespace Serein.NodeFlow.Model.Library
{
/// <summary>
/// 流程依赖加载
/// </summary>
public class FlowLibraryAssemblyContext : AssemblyLoadContext
{
private readonly AssemblyDependencyResolver _resolver;
/// <summary>
/// 创建新的加载上下文
/// </summary>
/// <param name="sereinFlowLibraryPath">类库路径</param>
/// <param name="name"></param>
public FlowLibraryAssemblyContext(string sereinFlowLibraryPath, string name) : base(name, isCollectible: true)
{
_resolver = new AssemblyDependencyResolver(sereinFlowLibraryPath);
}
protected override Assembly? Load(AssemblyName assemblyName)
{
string? assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName);
if (!string.IsNullOrEmpty(assemblyPath))
{
var assembly = Default.LoadFromAssemblyPath(assemblyPath);
//var assembly = LoadFromAssemblyPath(assemblyPath);
return assembly;
}
else
{
return Default.Assemblies.FirstOrDefault(x => x.FullName == assemblyName.FullName);
}
}
}
}

View File

@@ -1,10 +1,4 @@
using Microsoft.CodeAnalysis.CSharp.Syntax; using Serein.Library.Utils;
using Serein.Library.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Serein.Extend.NewtonsoftJson namespace Serein.Extend.NewtonsoftJson
{ {

View File

@@ -5,6 +5,15 @@
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<LangVersion>latest</LangVersion> <LangVersion>latest</LangVersion>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<BaseOutputPath>..\.\.Output</BaseOutputPath>
<Title>为 SereinFlow 提供的 JSON 扩展</Title>
<Version>1.0.0</Version>
<Description>通过 NewtonsoftJson 实现JSON门户扩展用于解决 Serein.Proto.* 项目下需要 JSON 序列化与反序列化的场景</Description>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@@ -25,7 +25,7 @@
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.11.0" PrivateAssets="all" /> <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.13.0" PrivateAssets="all" />
</ItemGroup> </ItemGroup>
<!--<ItemGroup> <!--<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.11.0"> <PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.11.0">

View File

@@ -10,10 +10,10 @@ namespace Serein.Proto.Modbus
/// 创建 Modbus 客户端实例 /// 创建 Modbus 客户端实例
/// </summary> /// </summary>
/// <param name="connectionString"> /// <param name="connectionString">
/// 连接字符串格式: /// <para>连接字符串格式: </para>
/// TCP示例"tcp:192.168.1.100:502" /// <para>TCP示例"tcp:192.168.1.100:502" </para>
/// UCP示例"ucp:192.168.1.100:502" /// <para>UCP示例"ucp:192.168.1.100:502" </para>
/// RTU示例"rtu:COM3:9600:1" 格式rtu:串口名:波特率:从站地址) /// <para>RTU示例"rtu:COM3:9600:1" 格式rtu:串口名:波特率:从站地址) </para>
/// </param> /// </param>
public static IModbusClient Create(string connectionString) public static IModbusClient Create(string connectionString)
{ {

View File

@@ -5,6 +5,15 @@
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<LangVersion>latest</LangVersion> <LangVersion>latest</LangVersion>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<BaseOutputPath>..\.\.Output</BaseOutputPath>
<Title>全异步Modbus协议客户端工具包</Title>
<Version>1.0.0</Version>
<Description>提供TCP、UDP、RTU三种方式客户端创建方式IModbusClient client = ModbusClientFactory.Create...;</Description>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@@ -5,6 +5,15 @@
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<LangVersion>latest</LangVersion> <LangVersion>latest</LangVersion>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<BaseOutputPath>..\.\.Output</BaseOutputPath>
<Title>基于Json数据载体的WebSocket交互工具包</Title>
<Version>1.0.0</Version>
<Description>基于Json数据载体的WebSocket交互工具包</Description>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@@ -1,13 +1,4 @@
using Microsoft.CodeAnalysis.CSharp.Syntax; namespace Serein.Script
using Serein.Library.Api;
using Serein.Script.Node;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Serein.Script
{ {
internal static class NodeInterpreterExtension internal static class NodeInterpreterExtension
{ {

View File

@@ -5,6 +5,15 @@
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<BaseOutputPath>..\.\.Output</BaseOutputPath> <BaseOutputPath>..\.\.Output</BaseOutputPath>
<Title>基于AST实现的脚本语言</Title>
<Version>1.0.0</Version>
<Description>使用了Emit构造委托缓存调用性能客观。提供了类型推导、转换C#代码功能。用于流程图中脚本处理,也可在其他地方进行使用。</Description>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageReadmeFile>README.md</PackageReadmeFile>
<RepositoryUrl>https://github.com/fhhyyp/serein-flow</RepositoryUrl>
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
@@ -18,7 +27,16 @@
<None Remove="TestExpression\**" /> <None Remove="TestExpression\**" />
<None Remove="Tool\**" /> <None Remove="Tool\**" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<None Include="..\LICENSE">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
<None Include="..\README.md">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
</ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Remove="Node\ExpressionNode.cs" /> <Compile Remove="Node\ExpressionNode.cs" />
</ItemGroup> </ItemGroup>

View File

@@ -1,14 +1,7 @@
using Microsoft.CodeAnalysis.CSharp.Syntax; using Serein.Library;
using Serein.Library;
using Serein.Library.Api;
using Serein.Script.Node; using Serein.Script.Node;
using Serein.Script.Node.FlowControl; using Serein.Script.Node.FlowControl;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace Serein.Script namespace Serein.Script
{ {

View File

@@ -269,9 +269,8 @@ namespace Serein.Script
} }
ASTNode tempNode = peekToken3.Type switch ASTNode tempNode = peekToken3.Type switch
{ {
TokenType.Dot => ParseMemberAccessNode(source), // 获取对象中的成员 source.Value... TokenType.Dot or TokenType.Semicolon or TokenType.ParenthesisRight =>
TokenType.Semicolon => ParseMemberAccessNode(source), // 获取对象中的成员 source.Value... ParseMemberAccessNode(source), // 获取对象中的成员 source.Value...
TokenType.ParenthesisRight => ParseMemberAccessNode(source), // 获取对象中的成员 source.Value...
TokenType.SquareBracketsLeft => ParseCollectionIndexNode(source), // 获取集合中的元素 source[index].... TokenType.SquareBracketsLeft => ParseCollectionIndexNode(source), // 获取集合中的元素 source[index]....
TokenType.ParenthesisLeft => ParseMemberFunctionCallNode(source), // 获取需要调用的方法 source(arg1,arg2...)... TokenType.ParenthesisLeft => ParseMemberFunctionCallNode(source), // 获取需要调用的方法 source(arg1,arg2...)...
_ => throw new Exception($"无法从对象获取成员当前Token类型为 {peekToken.Type}。") _ => throw new Exception($"无法从对象获取成员当前Token类型为 {peekToken.Type}。")
@@ -963,11 +962,9 @@ namespace Serein.Script
var peekToken3 = _lexer.PeekToken(); var peekToken3 = _lexer.PeekToken();
ASTNode tempNode = peekToken3.Type switch ASTNode tempNode = peekToken3.Type switch
{ {
TokenType.Comma => ParseMemberAccessNode(source), // 获取对象中的成员 source.Value... TokenType.Comma or TokenType.Operator or TokenType.Dot or TokenType.Semicolon or TokenType.ParenthesisRight
TokenType.Operator => ParseMemberAccessNode(source), // 获取对象中的成员 source.Value... => ParseMemberAccessNode(source), // 获取对象中的成员 source.Value...
TokenType.Dot => ParseMemberAccessNode(source), // 获取对象中的成员 source.Value...
TokenType.Semicolon => ParseMemberAccessNode(source), // 获取对象中的成员 source.Value...
TokenType.ParenthesisRight => ParseMemberAccessNode(source), // 获取对象中的成员 source.Value...
TokenType.SquareBracketsLeft => ParseCollectionIndexNode(source), // 获取集合中的元素 source[index].... TokenType.SquareBracketsLeft => ParseCollectionIndexNode(source), // 获取集合中的元素 source[index]....
TokenType.ParenthesisLeft => ParseMemberFunctionCallNode(source), // 获取需要调用的方法 source(arg1,arg2...)... TokenType.ParenthesisLeft => ParseMemberFunctionCallNode(source), // 获取需要调用的方法 source(arg1,arg2...)...
_ => throw new Exception($"无法从对象获取成员当前Token : {peekToken.ToString()}。") _ => throw new Exception($"无法从对象获取成员当前Token : {peekToken.ToString()}。")

View File

@@ -1,14 +1,10 @@
using Microsoft.CodeAnalysis.CSharp.Syntax; using Serein.Library;
using Serein.Library;
using Serein.Library.Api;
using Serein.Workbench.Api; using Serein.Workbench.Api;
using Serein.Workbench.Node.ViewModel; using Serein.Workbench.Node.ViewModel;
using Serein.Workbench.Themes; using Serein.Workbench.Themes;
using Serein.Workbench.Views;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Data; using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media; using System.Windows.Media;
namespace Serein.Workbench.Node.View namespace Serein.Workbench.Node.View

View File

@@ -1,14 +1,6 @@
using Microsoft.CodeAnalysis.CSharp.Syntax; using Serein.NodeFlow.Model;
using Serein.Library; using Serein.NodeFlow.Model.Library;
using Serein.NodeFlow;
using Serein.NodeFlow.Model;
using Serein.Workbench.Themes; using Serein.Workbench.Themes;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Documents;
using System.Windows.Input; using System.Windows.Input;
namespace Serein.Workbench.Node.ViewModel namespace Serein.Workbench.Node.ViewModel
@@ -71,9 +63,9 @@ public class FlowLibrary
}); });
} }
private static void OnCompileComplete(FlowLibrary flowLibrary) private static void OnCompileComplete(FlowLibraryCache flowLibrary)
{ {
var loadResult = flowLibrary.LoadAssembly(); // 动态编译完成后加载程序集 var loadResult = flowLibrary.LoadFlowMethod(); // 动态编译完成后加载程序集
if (!loadResult) if (!loadResult)
{ {
return ; return ;

View File

@@ -181,7 +181,7 @@ namespace Serein.Workbench.Services
SereinEnv.WriteLine(InfoType.INFO, "项目文件保存路径:" + savePath); SereinEnv.WriteLine(InfoType.INFO, "项目文件保存路径:" + savePath);
for (int index = 0; index < project.Librarys.Length; index++) for (int index = 0; index < project.Librarys.Length; index++)
{ {
NodeLibraryInfo? library = project.Librarys[index]; FlowLibraryInfo? library = project.Librarys[index];
string sourceFilePath = new Uri(library.FilePath).LocalPath; // 源文件夹 string sourceFilePath = new Uri(library.FilePath).LocalPath; // 源文件夹
string targetDir = System.IO.Path.Combine(librarySavePath, library.AssemblyName); // 目标文件夹 string targetDir = System.IO.Path.Combine(librarySavePath, library.AssemblyName); // 目标文件夹
if (!Path.Exists(targetDir)) if (!Path.Exists(targetDir))

View File

@@ -1,5 +1,5 @@
using Microsoft.Win32; using Microsoft.Win32;
using Serein.NodeFlow; using Serein.NodeFlow.Model.Library;
using Serein.NodeFlow.Tool; using Serein.NodeFlow.Tool;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -34,7 +34,7 @@ namespace Serein.Workbench.Themes
/// <summary> /// <summary>
/// 编译成功回调 /// 编译成功回调
/// </summary> /// </summary>
public Action<FlowLibrary> OnCompileComplete { get; set; } public Action<FlowLibraryCache> OnCompileComplete { get; set; }
public DynamicCompilerView() public DynamicCompilerView()
{ {
InitializeComponent(); InitializeComponent();
@@ -132,7 +132,7 @@ namespace Serein.Workbench.Themes
var path = textboxAssemblyName.Text; var path = textboxAssemblyName.Text;
Assembly assembly = _compiler.Compile(code, path); Assembly assembly = _compiler.Compile(code, path);
FlowLibrary flowLibrary = new FlowLibrary(assembly, path); FlowLibraryCache flowLibrary = new FlowLibraryCache(assembly, path);
if (assembly != null) if (assembly != null)
{ {

View File

@@ -19,13 +19,13 @@ namespace Serein.Workbench.ViewModels
private readonly IFlowEEForwardingService flowEEForwardingService; private readonly IFlowEEForwardingService flowEEForwardingService;
private readonly IFlowEnvironment flowEnvironment; private readonly IFlowEnvironment flowEnvironment;
[ObservableProperty] [ObservableProperty]
private ObservableCollection<FlowLibraryInfo> flowLibraryInfos; private ObservableCollection<Models.FlowLibraryInfo> flowLibraryInfos;
public FlowLibrarysViewModel(IFlowEEForwardingService flowEEForwardingService,IFlowEnvironment flowEnvironment) public FlowLibrarysViewModel(IFlowEEForwardingService flowEEForwardingService,IFlowEnvironment flowEnvironment)
{ {
this.flowEEForwardingService = flowEEForwardingService; this.flowEEForwardingService = flowEEForwardingService;
this.flowEnvironment = flowEnvironment; this.flowEnvironment = flowEnvironment;
FlowLibraryInfos = new ObservableCollection<FlowLibraryInfo>(); FlowLibraryInfos = new ObservableCollection<Models.FlowLibraryInfo>();
flowEEForwardingService.DllLoad += FlowEEForwardingService_OnDllLoad; flowEEForwardingService.DllLoad += FlowEEForwardingService_OnDllLoad;
} }
/// <summary> /// <summary>
@@ -48,15 +48,15 @@ namespace Serein.Workbench.ViewModels
private void FlowEEForwardingService_OnDllLoad(Library.Api.LoadDllEventArgs eventArgs) private void FlowEEForwardingService_OnDllLoad(Library.Api.LoadDllEventArgs eventArgs)
{ {
if (!eventArgs.IsSucceed) return; if (!eventArgs.IsSucceed) return;
List<MethodDetailsInfo> mds = eventArgs.MethodDetailss; List<MethodDetailsInfo> mds = eventArgs.NodeLibraryInfo.MethodInfos.ToList() ;
NodeLibraryInfo libraryInfo = eventArgs.NodeLibraryInfo; Library.FlowLibraryInfo libraryInfo = eventArgs.NodeLibraryInfo;
var methodInfo = new ObservableCollection<MethodDetailsInfo>(); var methodInfo = new ObservableCollection<MethodDetailsInfo>();
foreach (var md in mds) foreach (var md in mds)
{ {
methodInfo.Add(md); methodInfo.Add(md);
} }
var flInfo = new FlowLibraryInfo var flInfo = new Models.FlowLibraryInfo
{ {
LibraryName = libraryInfo.AssemblyName, LibraryName = libraryInfo.AssemblyName,
FilePath = libraryInfo.FilePath, FilePath = libraryInfo.FilePath,