重写了Script的解释器代码,使其更加直观。重写了流程控制的部分代码,分离运行环境IOC与流程IOC。

This commit is contained in:
fengjiayi
2025-07-18 22:45:06 +08:00
parent 88de5a21f5
commit fc05cd662b
38 changed files with 567 additions and 1418 deletions

View File

@@ -17,10 +17,11 @@ namespace Serein.Library.Api
string Guid {get; }
/// <summary>
/// 运行环境包含IOC容器。
/// 运行环境
/// </summary>
IFlowEnvironment Env { get; }
/// <summary>
/// 是否正在运行
/// </summary>

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Serein.Library.Api
@@ -8,6 +9,13 @@ namespace Serein.Library.Api
/// </summary>
public interface IFlowControl
{
/// <summary>
/// <para>单例模式IOC容器内部维护了一个实例字典默认使用类型的FullName作为Key如果以“接口-实现类”的方式注册那么将使用接口类型的FullName作为Key。</para>
/// <para>当某个类型注册绑定成功后,将不会因为其它地方尝试注册相同类型的行为导致类型被重新创建。</para>
/// </summary>
ISereinIOC IOC { get; }
/// <summary>
/// <para>需要你提供一个由你实现的ISereinIOC接口实现类</para>
/// <para>当你将流程运行环境集成在你的项目时,并希望流程运行时使用你提供的对象,而非自动创建</para>
@@ -15,7 +23,8 @@ namespace Serein.Library.Api
/// <para>注意,是流程运行时,而非运行环境</para>
/// </summary>
/// <param name="ioc"></param>
void UseExternalIOC(ISereinIOC ioc);
/// <param name="setDefultMemberOnReset">用于每次启动时重置IOC后默认注册某些类型</param>
void UseExternalIOC(ISereinIOC ioc, Action<ISereinIOC> setDefultMemberOnReset = null);
/// <summary>
/// 开始运行流程

View File

@@ -759,8 +759,7 @@ namespace Serein.Library.Api
/// <summary>
/// <para>单例模式IOC容器内部维护了一个实例字典默认使用类型的FullName作为Key如果以“接口-实现类”的方式注册那么将使用接口类型的FullName作为Key。</para>
/// <para>当某个类型注册绑定成功后,将不会因为其它地方尝试注册相同类型的行为导致类型被重新创建。</para>
/// <para>运行环境使用的IOC默认情况下无需对其进行调用</para>
/// </summary>
ISereinIOC IOC { get; }

View File

@@ -15,7 +15,8 @@ namespace Serein.Library
/// <summary>
/// 动态流程上下文
/// </summary>
/// <param name="flowEnvironment"></param>
/// <param name="flowEnvironment">脚本运行时的IOC</param>
/// <param name="ioc">脚本运行时使用的IOC容器</param>
public DynamicContext(IFlowEnvironment flowEnvironment)
{
Env = flowEnvironment;

View File

@@ -372,6 +372,8 @@ namespace Serein.Library
private readonly IFlowEnvironment flowEnvironment;
public static Serein.Library.Utils.ObjectPool<IDynamicContext> FlowContextPool { get; set; }
public ISereinIOC IOC => throw new NotImplementedException();
public LightweightFlowControl(IFlowCallTree flowCallTree, IFlowEnvironment flowEnvironment)
{
this.flowCallTree = flowCallTree;
@@ -479,6 +481,11 @@ namespace Serein.Library
{
throw new NotImplementedException();
}
public void UseExternalIOC(ISereinIOC ioc, Action<ISereinIOC> setDefultMemberOnReset = null)
{
throw new NotImplementedException();
}
#endregion
}

View File

@@ -3,6 +3,7 @@ using Serein.Library.Api;
using Serein.Library.Utils;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Threading.Tasks;
@@ -77,7 +78,8 @@ namespace Serein.Library
partial void OnIsInterruptChanged(bool oldValue, bool newValue)
{
if (newValue && _getInterruptTask is null)
Debug.WriteLine($" {nameof(NodeDebugSetting)}.{nameof(NodeDebugSetting.OnIsInterruptChanged)} 暂未实现,需要重新设计中断逻辑");
/*if (newValue && _getInterruptTask is null)
{
// 设置获取中断的委托
_getInterruptTask = () => NodeModel.Env.IOC.Get<FlowInterruptTool>().WaitTriggerAsync(NodeModel.Guid);
@@ -97,7 +99,7 @@ namespace Serein.Library
_getInterruptTask = null;
}
}
}*/
}

View File

@@ -335,7 +335,7 @@ namespace Serein.Library
#region -
/*#region “枚举-类型”转换器
if (ExplicitType is not null && ExplicitType.IsEnum && DataType != ExplicitType)
{
var resultEnum = Enum.Parse(ExplicitType, DataValue);
@@ -347,7 +347,7 @@ namespace Serein.Library
return value;
}
}
#endregion
#endregion*/
// 需要获取预入参数据
object inputParameter;

View File

@@ -128,6 +128,7 @@ namespace Serein.Library.Utils
total += ms;
Console.WriteLine($"运行1次耗时 :{total} 毫秒:");
Debug.WriteLine($"运行1次耗时 :{total} 毫秒:");
return result;
}
}

View File

@@ -17,15 +17,26 @@ namespace Serein.Library.Utils
public class EmitMethodInfo
{
/// <summary>
/// 方法声明类型
/// </summary>
public Type DeclaringType { get; set; }
/// <summary>
/// 方法类型
/// </summary>
public EmitMethodType EmitMethodType { get; set; }
/// <summary>
/// 是异步方法
/// </summary>
public bool IsTask { get; set; }
public bool IsAsync { get; set; }
/// <summary>
/// 是静态的
/// </summary>
public bool IsStatic { get; set; }
}
public enum EmitMethodType
@@ -41,16 +52,7 @@ namespace Serein.Library.Utils
/// <summary>
/// 有返回值的异步方法
/// </summary>
HasResultTask,
/// <summary>
/// 普通的方法。如果方法返回void时将会返回null。
/// </summary>
StaticFunc,
/// <summary>
/// 无返回值的异步方法
/// </summary>
StaticTask,
TaskHasResult,
}
public static bool IsGenericTask(Type returnType, out Type taskResult)
@@ -179,26 +181,31 @@ namespace Serein.Library.Utils
}
// 处理返回值如果没有返回值则返回null
il.Emit(OpCodes.Ret); // 返回
EmitMethodType emitMethodType;
if (IsTask)
{
if (IsTaskGenerics)
{
emitMethodType = EmitMethodType.TaskHasResult;
@delegate = dynamicMethod.CreateDelegate(typeof(Func<object, object[], Task<object>>));
}
else
{
emitMethodType = EmitMethodType.Task;
@delegate = dynamicMethod.CreateDelegate(typeof(Func<object, object[], Task>));
}
}
else
{
emitMethodType = EmitMethodType.Func;
@delegate = dynamicMethod.CreateDelegate(typeof(Func<object, object[], object>));
}
return new EmitMethodInfo
{
EmitMethodType = emitMethodType,
DeclaringType = methodInfo.DeclaringType,
IsTask = IsTask,
IsAsync = IsTask,
IsStatic = isStatic
};
}

View File

@@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Serein.Library.Utils
{
/// <summary>
/// 对于 linq 的异步扩展方法
/// </summary>
public static class LinqAsyncHelper
{
public static async Task<IEnumerable<TResult>> SelectAsync<TSource, TResult>(this IEnumerable<TSource> source,
Func<TSource, Task<TResult>> method)
{
return await Task.WhenAll(source.Select(async s => await method(s)));
}
public static async Task<IEnumerable<TResult>> SelectAsync<TSource, TResult>(this IEnumerable<TSource> source,
Func<TSource, Task<TResult>> method,
int concurrency = int.MaxValue)
{
var semaphore = new SemaphoreSlim(concurrency);
try
{
return await Task.WhenAll(source.Select(async s =>
{
try
{
await semaphore.WaitAsync();
return await method(s);
}
finally
{
semaphore.Release();
}
}));
}
finally
{
semaphore.Dispose();
}
}
}
}

View File

@@ -12,7 +12,7 @@ namespace Serein.Library.Utils
{
/// <summary>
/// 一个轻量级的IOC容器
/// 一个轻量级的单例IOC容器
/// </summary>
public class SereinIOC : ISereinIOC
{
@@ -45,7 +45,7 @@ namespace Serein.Library.Utils
public event IOCMembersChangedHandler OnIOCMembersChanged;
/// <summary>
/// 一个轻量级的IOC容器
/// 一个轻量级的D单例IOC容器
/// </summary>
public SereinIOC()
{

View File

@@ -1,70 +0,0 @@
using Net462DllTest.Signal;
using Net462DllTest.Trigger;
using Serein.Library;
using Serein.Library.Api;
using Serein.Library.Utils;
using System;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Net462DllTest.LogicControl
{
[AutoRegister]
[DynamicFlow("[View]")]
public class ViewLogicControl
{
private readonly ViewManagement ViewManagement;
public ViewLogicControl(ViewManagement ViewManagement)
{
this.ViewManagement = ViewManagement;
}
#region
[NodeAction(NodeType.Flipflop, "等待视图命令")]
public async Task<IFlipflopContext<int>> WaitTask(CommandSignal command)
{
var result = await ViewManagement.WaitTriggerWithTimeoutAsync<int>(command, TimeSpan.FromHours(10));
if (result.Type == TriggerDescription.Overtime)
{
return new FlipflopContext<int>(FlipflopStateType.Cancel, result.Value);
}
else
{
return new FlipflopContext<int>(FlipflopStateType.Succeed, result.Value);
}
}
#endregion
[NodeAction(NodeType.Action, "打开窗体(转换器)")]
public void OpenForm2([EnumTypeConvertor(typeof(FromValue))] Form form, bool isTop = true)
{
// 枚举转换为对应的Type并自动实例化
ViewManagement.OpenView(form, isTop);
}
[NodeAction(NodeType.Action, "关闭指定类型的所有窗体")]
public void CloseForm(IDynamicContext context, FromValue fromId = FromValue.FromWorkBenchView)
{
var fromType = EnumHelper.GetBoundValue<FromValue, Type>(fromId, attr => attr.Value);
if (fromType is null) return;
ViewManagement.CloseView(fromType);
}
}
}

View File

@@ -72,26 +72,12 @@
<Compile Include="Enums\PlcVarName.cs" />
<Compile Include="LogicControl\PlcLogicControl.cs" />
<Compile Include="LogicControl\ParkingLogicControl.cs" />
<Compile Include="LogicControl\ViewLogicControl.cs" />
<Compile Include="Enums\FromValue.cs" />
<Compile Include="Signal\CommandSignal.cs" />
<Compile Include="Signal\PLCVarSignal.cs" />
<Compile Include="Trigger\ViewManagement.cs" />
<Compile Include="Utils\GSModel.cs" />
<Compile Include="Utils\RelayCommand.cs" />
<Compile Include="ViewModel\FromWorkBenchViewModel.cs" />
<Compile Include="View\FromWorkBenchView.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="View\FromWorkBenchView.Designer.cs">
<DependentUpon>FromWorkBenchView.cs</DependentUpon>
</Compile>
<Compile Include="View\TestFormView.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="View\TestFormView.Designer.cs">
<DependentUpon>TestFormView.cs</DependentUpon>
</Compile>
<Compile Include="Web\FlowController.cs" />
<Compile Include="Web\PlcSocketService.cs" />
</ItemGroup>
@@ -101,14 +87,6 @@
<Name>Serein.Library</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="View\FromWorkBenchView.resx">
<DependentUpon>FromWorkBenchView.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="View\TestFormView.resx">
<DependentUpon>TestFormView.cs</DependentUpon>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<Folder Include="Properties\" />
</ItemGroup>

View File

@@ -1,110 +0,0 @@
namespace Net462DllTest
{
partial class FromWorkBenchView
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.textBoxPlcInfo = new System.Windows.Forms.TextBox();
this.button2 = new System.Windows.Forms.Button();
this.listBoxCommand = new System.Windows.Forms.ListBox();
this.textBoxSpaceNum = new System.Windows.Forms.TextBox();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(220, 56);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(65, 23);
this.button1.TabIndex = 0;
this.button1.Text = "查看状态";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// textBoxPlcInfo
//
this.textBoxPlcInfo.Location = new System.Drawing.Point(35, 24);
this.textBoxPlcInfo.Name = "textBoxPlcInfo";
this.textBoxPlcInfo.ReadOnly = true;
this.textBoxPlcInfo.Size = new System.Drawing.Size(250, 21);
this.textBoxPlcInfo.TabIndex = 1;
//
// button2
//
this.button2.Location = new System.Drawing.Point(205, 181);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(80, 23);
this.button2.TabIndex = 2;
this.button2.Text = "触发";
this.button2.UseVisualStyleBackColor = true;
this.button2.Click += new System.EventHandler(this.button2_Click);
//
// listBoxCommand
//
this.listBoxCommand.FormattingEnabled = true;
this.listBoxCommand.ItemHeight = 12;
this.listBoxCommand.Location = new System.Drawing.Point(35, 85);
this.listBoxCommand.Name = "listBoxCommand";
this.listBoxCommand.Size = new System.Drawing.Size(250, 88);
this.listBoxCommand.TabIndex = 6;
//
// textBoxSpaceNum
//
this.textBoxSpaceNum.Location = new System.Drawing.Point(35, 183);
this.textBoxSpaceNum.Name = "textBoxSpaceNum";
this.textBoxSpaceNum.Size = new System.Drawing.Size(106, 21);
this.textBoxSpaceNum.TabIndex = 7;
this.textBoxSpaceNum.Text = "104";
//
// FromWorkBenchView
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(341, 251);
this.Controls.Add(this.textBoxSpaceNum);
this.Controls.Add(this.listBoxCommand);
this.Controls.Add(this.button2);
this.Controls.Add(this.textBoxPlcInfo);
this.Controls.Add(this.button1);
this.Name = "FromWorkBenchView";
this.Text = "Form1";
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.FromWorkBenchView_FormClosing);
this.Load += new System.EventHandler(this.FromWorkBenchView_Load);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Button button1;
private System.Windows.Forms.TextBox textBoxPlcInfo;
private System.Windows.Forms.Button button2;
private System.Windows.Forms.ListBox listBoxCommand;
private System.Windows.Forms.TextBox textBoxSpaceNum;
}
}

View File

@@ -1,59 +0,0 @@
using Net462DllTest.Signal;
using Net462DllTest.ViewModel;
using Serein.Library;
using Serein.Library.Api;
using Serein.Library.Utils;
using System;
using System.Windows.Forms;
namespace Net462DllTest
{
public partial class FromWorkBenchView : Form
{
private FromWorkBenchViewModel ViewModel;
public FromWorkBenchView(IFlowEnvironment env)
{
InitializeComponent();
ViewModel = env.IOC.Get<FromWorkBenchViewModel>();
if (ViewModel is null)
{
SereinEnv.WriteLine(InfoType.INFO, "创建对象并注入依赖项");
ViewModel = env.IOC.CreateObject<FromWorkBenchViewModel>();
}
BindData();
}
private void BindData()
{
textBoxPlcInfo.DataBindings.Add(nameof(textBoxPlcInfo.Text), ViewModel, nameof(ViewModel.DeviceInfo), false, DataSourceUpdateMode.OnPropertyChanged);
textBoxSpaceNum.DataBindings.Add(nameof(textBoxSpaceNum.Text), ViewModel, nameof(ViewModel.SpcaeNumber), false, DataSourceUpdateMode.OnPropertyChanged);
listBoxCommand.DataSource = Enum.GetValues(typeof(CommandSignal));
listBoxCommand.DataBindings.Add(nameof(listBoxCommand.SelectedItem), ViewModel, nameof(ViewModel.SelectedSignal), false, DataSourceUpdateMode.OnPropertyChanged);
listBoxCommand.SelectedIndexChanged += (s, e) => listBoxCommand.DataBindings[nameof(listBoxCommand.SelectedItem)].WriteValue();
}
private void FromWorkBenchView_Load(object sender, EventArgs e)
{
}
private void FromWorkBenchView_FormClosing(object sender, FormClosingEventArgs e)
{
ViewModel.CommandCloseForm.Execute();
}
private void button2_Click(object sender, EventArgs e)
{
ViewModel.CommandGetParkingSpace.Execute();
}
private void button1_Click(object sender, EventArgs e)
{
ViewModel.CommandViewPlcInfo.Execute();
}
}
}

View File

@@ -1,120 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -1,62 +0,0 @@
using System;
namespace Net462DllTest.View
{
partial class TestFormView
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(167, 58);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(75, 23);
this.button1.TabIndex = 0;
this.button1.Text = "测试";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// TestFormView
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(254, 118);
this.Controls.Add(this.button1);
this.Name = "TestFormView";
this.Text = "TeseForm";
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Button button1;
}
}

View File

@@ -1,19 +0,0 @@
using System;
using System.Windows.Forms;
namespace Net462DllTest.View
{
public partial class TestFormView : Form
{
public TestFormView()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
}
}
}

View File

@@ -1,120 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -1,140 +0,0 @@
using Net462DllTest.Model;
using Net462DllTest.Signal;
using Net462DllTest.Trigger;
using Net462DllTest.Utils;
using Serein.Library.Network.WebSocketCommunication;
using System.ComponentModel;
namespace Net462DllTest.ViewModel
{
public class LibSpace
{
public string SpaceNum { get; set; }
public string PlateNumber { get; set; }
public override string ToString()
{
return $"{nameof(SpaceNum)}{SpaceNum}{nameof(PlateNumber)}{PlateNumber}";
}
}
public class FromWorkBenchViewModel : INotifyPropertyChanged
{
private readonly SiemensPlcDevice Device;
private readonly ViewManagement viewManagement;
private readonly PlcVarModelDataProxy plcVarModelDataProxy;
public FromWorkBenchViewModel(SiemensPlcDevice Device,
ViewManagement viewManagement,
PlcVarModelDataProxy plcVarModelDataProxy,
WebSocketServer webSocketServer)
{
this.Device = Device;
this.viewManagement = viewManagement;
this.plcVarModelDataProxy = plcVarModelDataProxy;
InitCommand(); // 初始化指令
}
#region
private string _spcaeNumber;
public string SpcaeNumber
{
get { return _spcaeNumber; }
set
{
if (_spcaeNumber != value)
{
_spcaeNumber = value;
OnPropertyChanged(nameof(SpcaeNumber));
}
}
}
private CommandSignal _selectedSignal;
public CommandSignal SelectedSignal
{
get { return _selectedSignal; }
set
{
if (_selectedSignal != value)
{
_selectedSignal = value;
OnPropertyChanged(nameof(SelectedSignal));
}
}
}
private string _deviceInfo;
public string DeviceInfo
{
get { return _deviceInfo; }
set
{
if (_deviceInfo != value)
{
_deviceInfo = value;
OnPropertyChanged(nameof(DeviceInfo));
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
#region
/// <summary>
/// 查看PLC信息
/// </summary>
public RelayCommand CommandViewPlcInfo { get; private set; }
/// <summary>
/// 调取车位
/// </summary>
public RelayCommand CommandGetParkingSpace { get; private set; }
/// <summary>
/// 关闭窗体
/// </summary>
public RelayCommand CommandCloseForm { get; private set; }
public void InitCommand()
{
CommandViewPlcInfo = new RelayCommand((p) =>
{
DeviceInfo = Device?.ToString();
});
CommandGetParkingSpace = new RelayCommand((p) =>
{
_ = viewManagement.InvokeTriggerAsync(SelectedSignal, SpcaeNumber);
});
CommandCloseForm = new RelayCommand((p) =>
{
});
}
#endregion
}
}

View File

@@ -33,23 +33,25 @@ namespace Net462DllTest.Web
[NodeAction(NodeType.Init)]
public void Init(IDynamicContext context)
{
context.Env.IOC.Register<WebSocketServer>();
context.Env.IOC.Register<WebSocketClient>();
var ioc = context.Env.FlowControl.IOC;
ioc.Register<WebSocketServer>();
ioc.Register<WebSocketClient>();
context.Env.IOC.Register<IRouter, Router>();
context.Env.IOC.Register<WebApiServer>();
ioc.Register<IRouter, Router>();
ioc.Register<WebApiServer>();
}
[NodeAction(NodeType.Loading)] // Loading 初始化完成已注入依赖项,可以开始逻辑上的操作
public void Loading(IDynamicContext context)
{
var ioc = context.Env.FlowControl.IOC;
// 注册控制器
context.Env.IOC.Run<IRouter, WebApiServer>((router, apiServer) => {
ioc.Run<IRouter, WebApiServer>((router, apiServer) => {
router.AddHandle(typeof(FlowController));
apiServer.Start("http://*:8089/"); // 开启 Web Api 服务
});
context.Env.IOC.Run<WebSocketServer>(async (socketServer) => {
ioc.Run<WebSocketServer>(async (socketServer) => {
socketServer.MsgHandleHelper.AddModule(this, (ex, recover) =>
{
recover(new
@@ -61,7 +63,7 @@ namespace Net462DllTest.Web
});
await socketServer.StartAsync("http://localhost:5005/"); // 开启 Web Socket 监听
});
context.Env.IOC.Run<WebSocketClient>(async client => {
ioc.Run<WebSocketClient>(async client => {
await client.ConnectAsync("ws://localhost:5005/"); // 连接到服务器
});
}
@@ -69,12 +71,13 @@ namespace Net462DllTest.Web
[NodeAction(NodeType.Exit)] // 流程结束时自动执行
public void Exit(IDynamicContext context)
{
context.Env.IOC.Run<WebApiServer>((apiServer) =>
var ioc = context.Env.FlowControl.IOC;
ioc.Run<WebApiServer>((apiServer) =>
{
apiServer?.Stop(); // 关闭 Web 服务
});
context.Env.IOC.Run<WebSocketServer>((socketServer) =>
ioc.Run<WebSocketServer>((socketServer) =>
{
socketServer.MsgHandleHelper.RemoveModule(this);
socketServer?.Stop(); // 关闭 Web 服务

View File

@@ -35,19 +35,44 @@ namespace Serein.NodeFlow.Env
this.flowOperationService = flowOperationService;
this.flowModelService = flowModelService;
this.UIContextOperation = UIContextOperation;
contexts = new ObjectPool<IDynamicContext>(() => new DynamicContext(flowEnvironment));
}
private ObjectPool<IDynamicContext> contexts;
private FlowWorkManagement flowWorkManagement;
private ISereinIOC sereinIOC;
private ISereinIOC externalIOC;
private Action<ISereinIOC> setDefultMemberOnReset;
private bool IsUseExternalIOC = false;
private object lockObj = new object();
/// <summary>
/// 如果全局触发器还在运行,则为 Running 。
/// </summary>
private RunState FlipFlopState = RunState.NoStart;
/// <summary>
/// 运行时的IOC容器
/// </summary>
public ISereinIOC IOC
{
get
{
lock (lockObj)
{
if (externalIOC is null) externalIOC = new SereinIOC();
return externalIOC;
}
}
private set
{
lock (lockObj)
{
externalIOC = value;
}
}
}
/// <inheritdoc/>
public async Task<bool> StartFlowAsync(string[] canvasGuids)
{
@@ -104,13 +129,14 @@ namespace Serein.NodeFlow.Env
flowTasks.Add(guid, ft);
}
#endregion
sereinIOC.Reset();
sereinIOC.Register<IFlowEnvironment>(() => flowEnvironment);
sereinIOC.Register<IScriptFlowApi, ScriptFlowApi>(); // 注册脚本接口
IOC.Reset();
setDefultMemberOnReset?.Invoke(IOC);
IOC.Register<IFlowEnvironment>(() => flowEnvironment);
//externalIOC.Register<IScriptFlowApi, ScriptFlowApi>(); // 注册脚本接口
var flowTaskOptions = new FlowWorkOptions
{
FlowIOC = IOC,
Environment = flowEnvironment, // 流程
Flows = flowTasks,
FlowContextPool = contexts, // 上下文对象池
@@ -143,9 +169,9 @@ namespace Serein.NodeFlow.Env
/// <inheritdoc/>
public async Task<TResult> StartFlowAsync<TResult>(string startNodeGuid)
{
var flowTaskOptions = new FlowWorkOptions
{
FlowIOC = IOC,
Environment = flowEnvironment, // 流程
FlowContextPool = contexts, // 上下文对象池
};
@@ -203,7 +229,7 @@ namespace Serein.NodeFlow.Env
{
flowWorkManagement?.Exit();
UIContextOperation?.Invoke(() => flowEnvironmentEvent.OnFlowRunComplete(new FlowEventArgs()));
sereinIOC.Reset();
IOC.Reset();
flowWorkManagement = null;
GC.Collect();
return Task.FromResult(true);
@@ -240,9 +266,11 @@ namespace Serein.NodeFlow.Env
}*/
}
/// <inheritdoc/>
public void UseExternalIOC(ISereinIOC ioc)
public void UseExternalIOC(ISereinIOC ioc, Action<ISereinIOC> setDefultMemberOnReset = null)
{
this.sereinIOC = ioc; // 设置IOC容器
IOC = ioc; // 设置IOC容器
this.setDefultMemberOnReset = setDefultMemberOnReset;
IsUseExternalIOC = true;
}
/// <inheritdoc/>
public void MonitorObjectNotification(string nodeGuid, object monitorData, MonitorObjectEventArgs.ObjSourceType sourceType)
@@ -270,10 +298,6 @@ namespace Serein.NodeFlow.Env
/// <inheritdoc/>
public async Task<TResult> InvokeAsync<TResult>(string apiGuid, Dictionary<string, object> dict)
{
if (sereinIOC is null)
{
sereinIOC = flowEnvironment.IOC;
}
if (!flowModelService.TryGetNodeModel(apiGuid, out var nodeModel))
{
throw new ArgumentNullException($"不存在流程接口:{apiGuid}");

View File

@@ -161,7 +161,7 @@ namespace Serein.NodeFlow.Env
}
#endregion
nodeModel = FlowNodeExtension.CreateNode(flowEnvironment, controlType, methodDetails); // 加载项目时创建节点
nodeModel = FlowNodeExtension.CreateNode(flowEnvironment.IOC, controlType, methodDetails); // 加载项目时创建节点
if (nodeModel is null)
{
nodeInfo.Guid = string.Empty;

View File

@@ -1,6 +1,7 @@
using Serein.Library;
using Serein.Library.Api;
using Serein.Library.Utils;
using Serein.NodeFlow.Env;
using Serein.NodeFlow.Model;
using System.Collections.Concurrent;
using System.ComponentModel;
@@ -51,18 +52,17 @@ namespace Serein.NodeFlow
/// <summary>
/// 创建节点
/// </summary>
/// <param name="env">运行环境</param>
/// <param name="envIOC">运行环境使用的IOC</param>
/// <param name="nodeControlType">节点类型</param>
/// <param name="methodDetails">方法描述</param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public static IFlowNode CreateNode(IFlowEnvironment env, NodeControlType nodeControlType,
MethodDetails? methodDetails = null)
public static IFlowNode CreateNode(ISereinIOC envIOC, NodeControlType nodeControlType, MethodDetails? methodDetails = null)
{
// 尝试获取需要创建的节点类型
if (!env.FlowEdit.NodeMVVMManagement.TryGetType(nodeControlType, out var nodeMVVM) || nodeMVVM.ModelType == null)
var flowEdit = envIOC.Get<IFlowEdit>();
if (!flowEdit.NodeMVVMManagement.TryGetType(nodeControlType, out var nodeMVVM) || nodeMVVM.ModelType == null)
{
throw new Exception($"无法创建{nodeControlType}节点,节点类型尚未注册。");
}
@@ -70,7 +70,7 @@ namespace Serein.NodeFlow
// 生成实例
//var nodeObj = Activator.CreateInstance(nodeMVVM.ModelType, env);
var nodeObj = env.IOC.CreateObject(nodeMVVM.ModelType);
var nodeObj = envIOC.CreateObject(nodeMVVM.ModelType);
if (nodeObj is not IFlowNode nodeModel)
{
throw new Exception($"无法创建目标节点类型的实例[{nodeControlType}]");

View File

@@ -33,6 +33,10 @@ namespace Serein.NodeFlow
/// </summary>
public class FlowWorkOptions()
{
/// <summary>
/// 流程IOC容器
/// </summary>
public ISereinIOC FlowIOC { get; set; }
/// <summary>
/// 流程运行环境
/// </summary>
@@ -46,7 +50,7 @@ namespace Serein.NodeFlow
/// <summary>
/// 上下文线程池
/// </summary>
public Serein.Library.Utils.ObjectPool<IDynamicContext> FlowContextPool { get; set; }
public Serein.Library.Utils.ObjectPool<IDynamicContext> FlowContextPool { get; set; }
/// <summary>
/// 每个画布需要启用的节点

View File

@@ -141,11 +141,11 @@ namespace Serein.NodeFlow.Model
}
else
{
var instance = Env.IOC.Get(md.ActingInstanceType);
var instance = Env.FlowControl.IOC.Get(md.ActingInstanceType);
if (instance is null)
{
Env.IOC.Register(md.ActingInstanceType).Build();
instance = Env.IOC.Get(md.ActingInstanceType);
Env.FlowControl.IOC.Register(md.ActingInstanceType).Build();
instance = Env.FlowControl.IOC.Get(md.ActingInstanceType);
}
object[] args = await this.GetParametersAsync(context, token);
var result = await dd.InvokeAsync(instance, args);

View File

@@ -39,11 +39,11 @@ namespace Serein.NodeFlow.Model
throw new Exception("不存在对应委托");
}
var instance = context.Env.IOC.Get(md.ActingInstanceType);
var instance = Env.FlowControl.IOC.Get(md.ActingInstanceType);
if (instance is null)
{
Env.IOC.Register(md.ActingInstanceType).Build();
instance = Env.IOC.Get(md.ActingInstanceType);
Env.FlowControl.IOC.Register(md.ActingInstanceType).Build();
instance = Env.FlowControl.IOC.Get(md.ActingInstanceType);
}
await dd.InvokeAsync(instance, [context]);
var args = await this.GetParametersAsync(context, token);

View File

@@ -246,6 +246,10 @@ namespace Serein.NodeFlow.Model
}
else
{
/*var tempName = node.MethodDetails.MethodName;
var index = node.MethodDetails.MethodName.IndexOf('(');
var methodName = tempName[..(index - 1)];
return GetApiInvokeName(node, methodName);*/
FlowLibraryService service = node.Env.IOC.Get<FlowLibraryService>();
if (service.TryGetMethodInfo(md.AssemblyName, md.MethodName, out var methodInfo))
{

View File

@@ -73,7 +73,7 @@ namespace Serein.NodeFlow.Model.Operation
IFlowNode? nodeModel;
if (IsBaseNode)
{
nodeModel = FlowNodeExtension.CreateNode(flowEnvironment, NodeControlType); // 加载基础节点
nodeModel = FlowNodeExtension.CreateNode(flowEnvironment.IOC, NodeControlType); // 加载基础节点
}
else
{
@@ -89,7 +89,7 @@ namespace Serein.NodeFlow.Model.Operation
return false;
//throw new InvalidOperationException($"无法创建节点,因为没有找到{MethodDetailsInfo.AssemblyName}.{MethodDetailsInfo.MethodName}方法,请检查是否已加载对应程序集");
}
nodeModel = FlowNodeExtension.CreateNode(flowEnvironment, NodeControlType, methodDetails); // 一般的加载节点方法
nodeModel = FlowNodeExtension.CreateNode(flowEnvironment.IOC, NodeControlType, methodDetails); // 一般的加载节点方法
}
nodeModel.Guid ??= Guid.NewGuid().ToString();

View File

@@ -113,6 +113,7 @@ namespace Serein.NodeFlow.Services
private bool RegisterAllType(List<IFlowNode> nodes)
{
var env = WorkOptions.Environment;
var ioc = WorkOptions.FlowIOC;
@@ -127,7 +128,7 @@ namespace Serein.NodeFlow.Services
{
if (md.ActingInstanceType != null)
{
env.IOC.Register(md.ActingInstanceType);
ioc.Register(md.ActingInstanceType);
}
else
{
@@ -135,10 +136,10 @@ namespace Serein.NodeFlow.Services
isSuccessful = false ;
}
}
env.IOC.Build(); // 绑定初始化时注册的类型
ioc.Build(); // 绑定初始化时注册的类型
foreach (var md in allMds)
{
var instance = env.IOC.Get(md.ActingInstanceType);
var instance = ioc.Get(md.ActingInstanceType);
if (instance is null)
{
SereinEnv.WriteLine(InfoType.ERROR, $"{md.MethodName} - 无法获取类型[{md.ActingInstanceType}]的实例");
@@ -154,7 +155,7 @@ namespace Serein.NodeFlow.Services
var env = WorkOptions.Environment;
var initMds = WorkOptions.InitMds;
var pool = WorkOptions.FlowContextPool;
var ioc = WorkOptions.Environment.IOC;
var ioc = WorkOptions.FlowIOC;
foreach (var md in initMds) // 初始化
{
if (!env.TryGetDelegateDetails(md.AssemblyName, md.MethodName, out var dd)) // 流程运行初始化
@@ -167,7 +168,7 @@ namespace Serein.NodeFlow.Services
context.Reset();
pool.Free(context);
}
env.IOC.Build(); // 绑定初始化时注册的类型
ioc.Build(); // 绑定初始化时注册的类型
var isSuccessful = true;
return isSuccessful;
}
@@ -176,7 +177,7 @@ namespace Serein.NodeFlow.Services
var env = WorkOptions.Environment;
var loadMds = WorkOptions.LoadMds;
var pool = WorkOptions.FlowContextPool;
var ioc = WorkOptions.Environment.IOC;
var ioc = WorkOptions.FlowIOC;
foreach (var md in loadMds) // 加载时
{
if (!env.TryGetDelegateDetails(md.AssemblyName, md.MethodName, out var dd)) // 流程运行初始化
@@ -189,7 +190,7 @@ namespace Serein.NodeFlow.Services
context.Reset();
pool.Free(context);
}
env.IOC.Build(); // 绑定初始化时注册的类型
ioc.Build(); // 绑定初始化时注册的类型
var isSuccessful = true;
return isSuccessful;
@@ -199,7 +200,7 @@ namespace Serein.NodeFlow.Services
var env = WorkOptions.Environment;
var mds = WorkOptions.ExitMds;
var pool = WorkOptions.FlowContextPool;
var ioc = WorkOptions.Environment.IOC;
var ioc = WorkOptions.FlowIOC;
// var fit = ioc.Get<FlowInterruptTool>();
// fit.CancelAllTrigger(); // 取消所有中断

View File

@@ -13,7 +13,7 @@ namespace Serein.Script
IDynamicContext FlowContext { get; }
/// <summary>
/// 是否该退出了(由外部发出停止信号)
/// 是否该退出了(由 TokenSource 控制,用于响应外部发出停止信号)
/// </summary>
bool IsReturn { get; }
@@ -40,7 +40,7 @@ namespace Serein.Script
/// <param name="varName"></param>
/// <param name="value"></param>
/// <returns></returns>
bool SetVarValue(string varName, object value);
bool SetVarValue(string varName, object? value);
/// <summary>
/// 结束调用

View File

@@ -8,17 +8,16 @@ namespace Serein.Script.Node
{
/// <summary>
/// 赋值节点
/// 变量赋值节点
/// </summary>
public class AssignmentNode : ASTNode
{
/// <summary>
/// 变量名称
/// </summary>
//public string Variable { get; }
public ASTNode Target { get; }
/// <summary>
/// 对应的节点
/// 值来源
/// </summary>
public ASTNode Value { get; }

View File

@@ -14,7 +14,7 @@ namespace Serein.Script
/// <summary>
/// 定义的变量
/// </summary>
private Dictionary<string, object> _variables = new Dictionary<string, object>();
private Dictionary<string, object?> _variables = new Dictionary<string, object?>();
/// <summary>
/// 取消令牌源,用于控制脚本的执行

View File

@@ -13,4 +13,5 @@ namespace Serein.Script
Message = $"异常信息 : {message} ,代码在第{node.Row}行: {node.Code.Trim()}";
}
}
}

View File

@@ -10,6 +10,9 @@ using System.Threading.Tasks;
namespace Serein.Script
{
public class SereinScript
{
/// <summary>
@@ -47,7 +50,7 @@ namespace Serein.Script
}
Dictionary<ASTNode, Type> symbolInfos = TypeAnalysis.NodeSymbolInfos.ToDictionary();
SereinScriptInterpreter Interpreter = new SereinScriptInterpreter(symbolInfos);
return await Interpreter.InterpretAsync(context, programNode);
return await Interpreter.InterpreterAsync(context, programNode);
}

File diff suppressed because it is too large Load Diff

View File

@@ -198,7 +198,6 @@ namespace Serein.Script
this._index = token.StartIndex;
}
internal Token NextToken()
{
@@ -525,7 +524,6 @@ namespace Serein.Script
return ReadOnlySpan<char>.Empty;
}
public int GetIndex()
{
return _index;

View File

@@ -75,7 +75,6 @@ namespace Serein.Script
}
/// <summary>
/// 类型获取
/// </summary>
@@ -542,6 +541,8 @@ namespace Serein.Script
break;
case ObjectInstantiationNode objectInstantiationNode: // 类型实例化
break;
case CtorAssignmentNode ctorAssignmentNode:
break;
case ExpressionNode expressionNode: // 类型表达式(链式调用)
break;
case MemberAccessNode memberAccessNode: // 对象成员访问