diff --git a/Library/SerinExpression/ConditionResolver.cs b/Library/SerinExpression/ConditionResolver.cs
new file mode 100644
index 0000000..f95b47b
--- /dev/null
+++ b/Library/SerinExpression/ConditionResolver.cs
@@ -0,0 +1,337 @@
+using System.Reflection;
+
+namespace Serein.Library.SerinExpression
+{
+ ///
+ /// 条件解析抽象类
+ ///
+ public abstract class ConditionResolver
+ {
+ public abstract bool Evaluate(object obj);
+ }
+
+ public class PassConditionResolver : ConditionResolver
+ {
+ public Operator Op { get; set; }
+ public override bool Evaluate(object obj)
+ {
+ return Op switch
+ {
+ Operator.Pass => true,
+ Operator.NotPass => false,
+ _ => throw new NotSupportedException("不支持的条件类型")
+ };
+ }
+
+ public enum Operator
+ {
+ Pass,
+ NotPass,
+ }
+
+ }
+
+ public class ValueTypeConditionResolver : ConditionResolver where T : struct, IComparable
+ {
+ public enum Operator
+ {
+ ///
+ /// 不进行任何操作
+ ///
+ Node,
+ ///
+ /// 大于
+ ///
+ GreaterThan,
+ ///
+ /// 小于
+ ///
+ LessThan,
+ ///
+ /// 等于
+ ///
+ Equal,
+ ///
+ /// 大于或等于
+ ///
+ GreaterThanOrEqual,
+ ///
+ /// 小于或等于
+ ///
+ LessThanOrEqual,
+ ///
+ /// 在两者之间
+ ///
+ InRange,
+ ///
+ /// 不在两者之间
+ ///
+ OutOfRange
+ }
+
+ public Operator Op { get; set; }
+ public T Value { get; set; }
+ public T RangeStart { get; set; }
+ public T RangeEnd { get; set; }
+
+ public string ArithmeticExpression { get; set; }
+
+
+ public override bool Evaluate(object obj)
+ {
+ if (obj is T typedObj)
+ {
+ double numericValue = Convert.ToDouble(typedObj);
+ if (!string.IsNullOrEmpty(ArithmeticExpression))
+ {
+ numericValue = SerinArithmeticExpressionEvaluator.Evaluate(ArithmeticExpression, numericValue);
+ }
+
+ T evaluatedValue = (T)Convert.ChangeType(numericValue, typeof(T));
+
+ return Op switch
+ {
+ Operator.GreaterThan => evaluatedValue.CompareTo(Value) > 0,
+ Operator.LessThan => evaluatedValue.CompareTo(Value) < 0,
+ Operator.Equal => evaluatedValue.CompareTo(Value) == 0,
+ Operator.GreaterThanOrEqual => evaluatedValue.CompareTo(Value) >= 0,
+ Operator.LessThanOrEqual => evaluatedValue.CompareTo(Value) <= 0,
+ Operator.InRange => evaluatedValue.CompareTo(RangeStart) >= 0 && evaluatedValue.CompareTo(RangeEnd) <= 0,
+ Operator.OutOfRange => evaluatedValue.CompareTo(RangeStart) < 0 || evaluatedValue.CompareTo(RangeEnd) > 0,
+ _ => throw new NotSupportedException("不支持的条件类型")
+ };
+ /* switch (Op)
+ {
+ case Operator.GreaterThan:
+ return evaluatedValue.CompareTo(Value) > 0;
+ case Operator.LessThan:
+ return evaluatedValue.CompareTo(Value) < 0;
+ case Operator.Equal:
+ return evaluatedValue.CompareTo(Value) == 0;
+ case Operator.GreaterThanOrEqual:
+ return evaluatedValue.CompareTo(Value) >= 0;
+ case Operator.LessThanOrEqual:
+ return evaluatedValue.CompareTo(Value) <= 0;
+ case Operator.InRange:
+ return evaluatedValue.CompareTo(RangeStart) >= 0 && evaluatedValue.CompareTo(RangeEnd) <= 0;
+ case Operator.OutOfRange:
+ return evaluatedValue.CompareTo(RangeStart) < 0 || evaluatedValue.CompareTo(RangeEnd) > 0;
+ }*/
+ }
+ return false;
+ }
+ }
+
+ public class BoolConditionResolver : ConditionResolver
+ {
+ public enum Operator
+ {
+ ///
+ /// 是
+ ///
+ Is
+ }
+
+ public Operator Op { get; set; }
+ public bool Value { get; set; }
+
+ public override bool Evaluate(object obj)
+ {
+
+ if (obj is bool boolObj)
+ {
+ return boolObj == Value;
+ /*switch (Op)
+ {
+ case Operator.Is:
+ return boolObj == Value;
+ }*/
+ }
+ return false;
+ }
+ }
+
+ public class StringConditionResolver : ConditionResolver
+ {
+ public enum Operator
+ {
+ ///
+ /// 出现过
+ ///
+ Contains,
+ ///
+ /// 没有出现过
+ ///
+ DoesNotContain,
+ ///
+ /// 相等
+ ///
+ Equal,
+ ///
+ /// 不相等
+ ///
+ NotEqual,
+ ///
+ /// 起始字符串等于
+ ///
+ StartsWith,
+ ///
+ /// 结束字符串等于
+ ///
+ EndsWith
+ }
+
+ public Operator Op { get; set; }
+
+ public string Value { get; set; }
+
+
+ public override bool Evaluate(object obj)
+ {
+ if (obj is string strObj)
+ {
+ return Op switch
+ {
+ Operator.Contains => strObj.Contains(Value),
+ Operator.DoesNotContain => !strObj.Contains(Value),
+ Operator.Equal => strObj == Value,
+ Operator.NotEqual => strObj != Value,
+ Operator.StartsWith => strObj.StartsWith(Value),
+ Operator.EndsWith => strObj.EndsWith(Value),
+ _ => throw new NotSupportedException("不支持的条件类型"),
+ };
+
+ /* switch (Op)
+ {
+ case Operator.Contains:
+ return strObj.Contains(Value);
+ case Operator.DoesNotContain:
+ return !strObj.Contains(Value);
+ case Operator.Equal:
+ return strObj == Value;
+ case Operator.NotEqual:
+ return strObj != Value;
+ case Operator.StartsWith:
+ return strObj.StartsWith(Value);
+ case Operator.EndsWith:
+ return strObj.EndsWith(Value);
+ }*/
+ }
+ return false;
+ }
+ }
+ public class MemberConditionResolver : ConditionResolver where T : struct, IComparable
+ {
+ //public string MemberPath { get; set; }
+ public ValueTypeConditionResolver.Operator Op { get; set; }
+ public object? TargetObj { get; set; }
+ public T Value { get; set; }
+
+ public string ArithmeticExpression { get; set; }
+
+ public override bool Evaluate(object? obj)
+ {
+ //object? memberValue = GetMemberValue(obj, MemberPath);
+ if (TargetObj is T typedObj)
+ {
+ return new ValueTypeConditionResolver
+ {
+ Op = Op,
+ Value = Value,
+ ArithmeticExpression = ArithmeticExpression,
+ }.Evaluate(typedObj);
+ }
+ return false;
+ }
+
+ //private object? GetMemberValue(object? obj, string memberPath)
+ //{
+ // string[] members = memberPath[1..].Split('.');
+ // foreach (var member in members)
+ // {
+ // if (obj == null) return null;
+ // Type type = obj.GetType();
+ // PropertyInfo? propertyInfo = type.GetProperty(member);
+ // FieldInfo? fieldInfo = type.GetField(member);
+ // if (propertyInfo != null)
+ // obj = propertyInfo.GetValue(obj);
+ // else if (fieldInfo != null)
+ // obj = fieldInfo.GetValue(obj);
+ // else
+ // throw new ArgumentException($"Member {member} not found in type {type.FullName}");
+ // }
+ // return obj;
+ //}
+ }
+
+ public class MemberStringConditionResolver : ConditionResolver
+ {
+
+ public string MemberPath { get; set; }
+
+ public StringConditionResolver.Operator Op { get; set; }
+
+ public string Value { get; set; }
+
+
+ public override bool Evaluate(object obj)
+ {
+ object memberValue = GetMemberValue(obj, MemberPath);
+ if (memberValue is string strObj)
+ {
+ return new StringConditionResolver
+ {
+ Op = Op,
+ Value = Value
+ }.Evaluate(strObj);
+ }
+ return false;
+ }
+
+ private object GetMemberValue(object? obj, string memberPath)
+ {
+ string[] members = memberPath[1..].Split('.');
+ foreach (var member in members)
+ {
+
+ if (obj == null) return null;
+
+ Type type = obj.GetType();
+ PropertyInfo? propertyInfo = type.GetProperty(member);
+ FieldInfo? fieldInfo = type.GetField(member);
+ if (propertyInfo != null)
+ obj = propertyInfo.GetValue(obj);
+ else if (fieldInfo != null)
+ obj = fieldInfo.GetValue(obj);
+ else
+ throw new ArgumentException($"Member {member} not found in type {type.FullName}");
+ }
+
+ return obj;
+
+ }
+
+
+
+
+
+ private static string GetArithmeticExpression(string part)
+ {
+ int startIndex = part.IndexOf('[');
+ int endIndex = part.IndexOf(']');
+ if (startIndex >= 0 && endIndex > startIndex)
+ {
+ return part.Substring(startIndex + 1, endIndex - startIndex - 1);
+ }
+
+ return null;
+
+ }
+
+
+
+
+
+ }
+
+}
diff --git a/Library/SerinExpression/SerinConditionParser.cs b/Library/SerinExpression/SerinConditionParser.cs
new file mode 100644
index 0000000..5b9348e
--- /dev/null
+++ b/Library/SerinExpression/SerinConditionParser.cs
@@ -0,0 +1,337 @@
+using System.Globalization;
+using System.Reflection;
+
+namespace Serein.Library.SerinExpression;
+
+public class SerinConditionParser
+{
+ public static bool To(T data, string expression)
+ {
+ try
+ {
+
+ return ConditionParse(data, expression).Evaluate(data);
+
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine(ex);
+ throw;
+ }
+ }
+
+ public static ConditionResolver ConditionParse(object data, string expression)
+ {
+ if (expression.StartsWith('.')) // 表达式前缀属于从上一个节点数据对象获取成员值
+ {
+ return ParseObjectExpression(data, expression);
+ }
+ else
+ {
+ return ParseSimpleExpression(data, expression);
+ }
+
+
+ //bool ContainsArithmeticOperators(string expression)
+ //{
+ // return expression.Contains('+') || expression.Contains('-') || expression.Contains('*') || expression.Contains('/');
+ //}
+
+ }
+
+ ///
+ /// 获取计算表达式的部分
+ ///
+ ///
+ ///
+ private static string GetArithmeticExpression(string part)
+ {
+ int startIndex = part.IndexOf('[');
+ int endIndex = part.IndexOf(']');
+ if (startIndex >= 0 && endIndex > startIndex)
+ {
+ return part.Substring(startIndex + 1, endIndex - startIndex - 1);
+ }
+
+ return null;
+
+ }
+ ///
+ /// 获取对象指定名称的成员
+ ///
+ private static object? GetMemberValue(object? obj, string memberPath)
+ {
+ string[] members = memberPath[1..].Split('.');
+ foreach (var member in members)
+ {
+ if (obj == null) return null;
+ Type type = obj.GetType();
+ PropertyInfo? propertyInfo = type.GetProperty(member);
+ FieldInfo? fieldInfo = type.GetField(member);
+ if (propertyInfo != null)
+ obj = propertyInfo.GetValue(obj);
+ else if (fieldInfo != null)
+ obj = fieldInfo.GetValue(obj);
+ else
+ throw new ArgumentException($"Member {member} not found in type {type.FullName}");
+ }
+ return obj;
+ }
+ ///
+ /// 解析对象表达式
+ ///
+ private static ConditionResolver ParseObjectExpression(object data, string expression)
+ {
+ var parts = expression.Split(' ');
+ string operatorStr = parts[0];
+ string valueStr = string.Join(' ', parts, 1, parts.Length - 1);
+
+ int typeStartIndex = expression.IndexOf('<');
+ int typeEndIndex = expression.IndexOf('>');
+
+ string memberPath;
+ Type type;
+ object? targetObj;
+ if (typeStartIndex + typeStartIndex == -2)
+ {
+ memberPath = operatorStr;
+ targetObj = GetMemberValue(data, operatorStr);
+
+ type = targetObj.GetType();
+
+ operatorStr = parts[1].ToLower();
+ valueStr = string.Join(' ', parts.Skip(2));
+ }
+ else
+ {
+ if (typeStartIndex >= typeEndIndex)
+ {
+ throw new ArgumentException("无效的表达式格式");
+ }
+ memberPath = expression.Substring(0, typeStartIndex).Trim();
+ string typeStr = expression.Substring(typeStartIndex + 1, typeEndIndex - typeStartIndex - 1).Trim().ToLower();
+ parts = expression.Substring(typeEndIndex + 1).Trim().Split(' ');
+ if (parts.Length == 3)
+ {
+ operatorStr = parts[1].ToLower();
+ valueStr = string.Join(' ', parts.Skip(2));
+ }
+ else
+ {
+ operatorStr = parts[0].ToLower();
+ valueStr = string.Join(' ', parts.Skip(1));
+ }
+ targetObj = GetMemberValue(data, memberPath);
+
+ Type? tempType = typeStr switch
+ {
+ "int" => typeof(int),
+ "double" => typeof(double),
+ "bool" => typeof(bool),
+ "string" => typeof(string),
+ _ => Type.GetType(typeStr)
+ };
+ type = tempType ?? throw new ArgumentException("对象表达式无效的类型声明");
+ }
+
+
+
+ if (type == typeof(int))
+ {
+ int value = int.Parse(valueStr, CultureInfo.InvariantCulture);
+ return new MemberConditionResolver
+ {
+ TargetObj = targetObj,
+ //MemberPath = memberPath,
+ Op = ParseValueTypeOperator(operatorStr),
+ Value = value,
+ ArithmeticExpression = GetArithmeticExpression(parts[0])
+ };
+ }
+ else if (type == typeof(double))
+ {
+ double value = double.Parse(valueStr, CultureInfo.InvariantCulture);
+ return new MemberConditionResolver
+ {
+ //MemberPath = memberPath,
+ TargetObj = targetObj,
+ Op = ParseValueTypeOperator(operatorStr),
+ Value = value,
+ ArithmeticExpression = GetArithmeticExpression(parts[0])
+ };
+
+ }
+ else if (type == typeof(bool))
+ {
+ return new MemberConditionResolver
+ {
+ //MemberPath = memberPath,
+ TargetObj = targetObj,
+ Op = (ValueTypeConditionResolver.Operator)ParseBoolOperator(operatorStr)
+ };
+ }
+ else if (type == typeof(string))
+ {
+ return new MemberStringConditionResolver
+ {
+ MemberPath = memberPath,
+ Op = ParseStringOperator(operatorStr),
+ Value = valueStr
+ };
+ }
+
+ throw new NotSupportedException($"Type {type} is not supported.");
+ }
+
+ private static ConditionResolver ParseSimpleExpression(object data, string expression)
+ {
+ if ("pass".Equals(expression.ToLower()))
+ {
+ return new PassConditionResolver
+ {
+ Op = PassConditionResolver.Operator.Pass,
+ };
+ }
+ else
+ {
+ if ("not pass".Equals(expression.ToLower()))
+ {
+ return new PassConditionResolver
+ {
+ Op = PassConditionResolver.Operator.NotPass,
+ };
+ }
+ if ("!pass".Equals(expression.ToLower()))
+ {
+ return new PassConditionResolver
+ {
+ Op = PassConditionResolver.Operator.NotPass,
+ };
+ }
+ }
+
+
+ var parts = expression.Split(' ');
+
+ if (parts.Length < 2)
+ throw new ArgumentException("无效的表达式格式。");
+
+ //string typeStr = parts[0];
+ string operatorStr = parts[0];
+ string valueStr = string.Join(' ', parts, 1, parts.Length - 1);
+
+ Type type = data.GetType();//Type.GetType(typeStr);
+ if (type == typeof(int))
+ {
+ var op = ParseValueTypeOperator(operatorStr);
+ if (op == ValueTypeConditionResolver.Operator.InRange || op == ValueTypeConditionResolver.Operator.OutOfRange)
+ {
+ var temp = valueStr.Split('-');
+ if (temp.Length < 2)
+ throw new ArgumentException($"范围无效:{valueStr}。");
+ int rangeStart = int.Parse(temp[0], CultureInfo.InvariantCulture);
+ int rangeEnd = int.Parse(temp[1], CultureInfo.InvariantCulture);
+ return new ValueTypeConditionResolver
+ {
+ Op = op,
+ RangeStart = rangeStart,
+ RangeEnd = rangeEnd,
+ ArithmeticExpression = GetArithmeticExpression(parts[0]),
+ };
+ }
+ else
+ {
+ int value = int.Parse(valueStr, CultureInfo.InvariantCulture);
+ return new ValueTypeConditionResolver
+ {
+ Op = op,
+ Value = value,
+ ArithmeticExpression = GetArithmeticExpression(parts[0])
+ };
+
+ }
+
+ }
+ else if (type == typeof(double))
+ {
+ double value = double.Parse(valueStr, CultureInfo.InvariantCulture);
+ return new ValueTypeConditionResolver
+ {
+ Op = ParseValueTypeOperator(operatorStr),
+ Value = value,
+ ArithmeticExpression = GetArithmeticExpression(parts[0])
+ };
+ }
+ else if (type == typeof(bool))
+ {
+ bool value = bool.Parse(valueStr);
+ return new BoolConditionResolver
+ {
+ Op = ParseBoolOperator(operatorStr),
+ Value = value,
+ };
+ }
+ else if (type == typeof(string))
+ {
+ return new StringConditionResolver
+ {
+ Op = ParseStringOperator(operatorStr),
+ Value = valueStr
+ };
+ }
+
+ throw new NotSupportedException($"Type {type} is not supported.");
+ }
+
+
+ private static ValueTypeConditionResolver.Operator ParseValueTypeOperator(string operatorStr) where T : struct, IComparable
+ {
+ return operatorStr switch
+ {
+ ">" => ValueTypeConditionResolver.Operator.GreaterThan,
+ "<" => ValueTypeConditionResolver.Operator.LessThan,
+ "==" => ValueTypeConditionResolver.Operator.Equal,
+ ">=" => ValueTypeConditionResolver.Operator.GreaterThanOrEqual,
+ "≥" => ValueTypeConditionResolver.Operator.GreaterThanOrEqual,
+ "<=" => ValueTypeConditionResolver.Operator.LessThanOrEqual,
+ "≤" => ValueTypeConditionResolver.Operator.LessThanOrEqual,
+ "equals" => ValueTypeConditionResolver.Operator.Equal,
+ "in" => ValueTypeConditionResolver.Operator.InRange,
+ "!in" => ValueTypeConditionResolver.Operator.OutOfRange,
+ _ => throw new ArgumentException($"Invalid operator {operatorStr} for value type.")
+ };
+ }
+
+ private static BoolConditionResolver.Operator ParseBoolOperator(string operatorStr)
+ {
+ return operatorStr switch
+ {
+ "is" => BoolConditionResolver.Operator.Is,
+ "==" => BoolConditionResolver.Operator.Is,
+ "equals" => BoolConditionResolver.Operator.Is,
+ //"isFalse" => BoolConditionNode.Operator.IsFalse,
+ _ => throw new ArgumentException($"Invalid operator {operatorStr} for bool type.")
+ };
+ }
+
+ private static StringConditionResolver.Operator ParseStringOperator(string operatorStr)
+ {
+ return operatorStr switch
+ {
+ "c" => StringConditionResolver.Operator.Contains,
+ "nc" => StringConditionResolver.Operator.DoesNotContain,
+ "sw" => StringConditionResolver.Operator.StartsWith,
+ "ew" => StringConditionResolver.Operator.EndsWith,
+
+ "contains" => StringConditionResolver.Operator.Contains,
+ "doesNotContain" => StringConditionResolver.Operator.DoesNotContain,
+ "equals" => StringConditionResolver.Operator.Equal,
+ "==" => StringConditionResolver.Operator.Equal,
+ "notEquals" => StringConditionResolver.Operator.NotEqual,
+ "!=" => StringConditionResolver.Operator.NotEqual,
+ "startsWith" => StringConditionResolver.Operator.StartsWith,
+ "endsWith" => StringConditionResolver.Operator.EndsWith,
+ _ => throw new ArgumentException($"Invalid operator {operatorStr} for string type.")
+ };
+ }
+}
diff --git a/Library/SerinExpression/SerinExpressionEvaluator.cs b/Library/SerinExpression/SerinExpressionEvaluator.cs
new file mode 100644
index 0000000..97602c8
--- /dev/null
+++ b/Library/SerinExpression/SerinExpressionEvaluator.cs
@@ -0,0 +1,207 @@
+using System.Data;
+
+namespace Serein.Library.SerinExpression
+{
+ public class SerinArithmeticExpressionEvaluator
+ {
+ private static readonly DataTable table = new DataTable();
+
+ public static double Evaluate(string expression, double inputValue)
+ {
+ // 替换占位符@为输入值
+ expression = expression.Replace("@", inputValue.ToString());
+ try
+ {
+ // 使用 DataTable.Compute 方法计算表达式
+ var result = table.Compute(expression, string.Empty);
+ return Convert.ToDouble(result);
+ }
+ catch
+ {
+ throw new ArgumentException("Invalid arithmetic expression.");
+ }
+ }
+ }
+
+ public class SerinExpressionEvaluator
+ {
+ public static object Evaluate(string expression, object targetObJ, out bool IsChange)
+ {
+ var parts = expression.Split([' '], 2);
+ if (parts.Length != 2)
+ {
+ throw new ArgumentException("Invalid expression format.");
+ }
+
+ var operation = parts[0].ToLower();
+ var operand = parts[1][0] == '.' ? parts[1][1..] : parts[1];
+
+ var result = operation switch
+ {
+ "@num" => ComputedNumber(targetObJ, operand),
+ "@call" => InvokeMethod(targetObJ, operand),
+ "@get" => GetMember(targetObJ, operand),
+ "@set" => SetMember(targetObJ, operand),
+ _ => throw new NotSupportedException($"Operation {operation} is not supported.")
+ };
+
+ IsChange = operation switch
+ {
+ "@num" => true,
+ "@call" => true,
+ "@get" => true,
+ "@set" => false,
+ _ => throw new NotSupportedException($"Operation {operation} is not supported.")
+ };
+
+ return result;
+ }
+
+
+ private static readonly char[] separator = ['(', ')'];
+ private static readonly char[] separatorArray = [','];
+
+ private static object InvokeMethod(object target, string methodCall)
+ {
+ var methodParts = methodCall.Split(separator, StringSplitOptions.RemoveEmptyEntries);
+ if (methodParts.Length != 2)
+ {
+ throw new ArgumentException("Invalid method call format.");
+ }
+
+ var methodName = methodParts[0];
+ var parameterList = methodParts[1];
+ var parameters = parameterList.Split(separatorArray, StringSplitOptions.RemoveEmptyEntries)
+ .Select(p => p.Trim())
+ .ToArray();
+
+ var method = target.GetType().GetMethod(methodName);
+ if (method == null)
+ {
+ throw new ArgumentException($"Method {methodName} not found on target.");
+ }
+
+ var parameterValues = method.GetParameters()
+ .Select((p, index) => Convert.ChangeType(parameters[index], p.ParameterType))
+ .ToArray();
+
+
+ return method.Invoke(target, parameterValues);
+
+ }
+
+ private static object GetMember(object target, string memberPath)
+ {
+ var members = memberPath.Split('.');
+ foreach (var member in members)
+ {
+
+ if (target == null) return null;
+
+
+ var property = target.GetType().GetProperty(member);
+ if (property != null)
+ {
+
+ target = property.GetValue(target);
+
+ }
+ else
+ {
+ var field = target.GetType().GetField(member);
+ if (field != null)
+ {
+
+ target = field.GetValue(target);
+
+ }
+ else
+ {
+ throw new ArgumentException($"Member {member} not found on target.");
+ }
+ }
+ }
+
+
+ return target;
+
+ }
+
+ private static object SetMember(object target, string assignment)
+ {
+ var parts = assignment.Split(new[] { '=' }, 2);
+ if (parts.Length != 2)
+ {
+ throw new ArgumentException("Invalid assignment format.");
+ }
+
+ var memberPath = parts[0].Trim();
+ var value = parts[1].Trim();
+
+ var members = memberPath.Split('.');
+ for (int i = 0; i < members.Length - 1; i++)
+ {
+ var member = members[i];
+
+ var property = target.GetType().GetProperty(member);
+
+ if (property != null)
+ {
+
+ target = property.GetValue(target);
+
+ }
+ else
+ {
+ var field = target.GetType().GetField(member);
+ if (field != null)
+ {
+
+ target = field.GetValue(target);
+
+ }
+ else
+ {
+ throw new ArgumentException($"Member {member} not found on target.");
+ }
+ }
+ }
+
+ var lastMember = members.Last();
+
+ var lastProperty = target.GetType().GetProperty(lastMember);
+
+ if (lastProperty != null)
+ {
+ var convertedValue = Convert.ChangeType(value, lastProperty.PropertyType);
+ lastProperty.SetValue(target, convertedValue);
+ }
+ else
+ {
+ var lastField = target.GetType().GetField(lastMember);
+ if (lastField != null)
+ {
+ var convertedValue = Convert.ChangeType(value, lastField.FieldType);
+ lastField.SetValue(target, convertedValue);
+ }
+ else
+ {
+ throw new ArgumentException($"Member {lastMember} not found on target.");
+ }
+ }
+
+ return target;
+ }
+
+ private static double ComputedNumber(object value, string expression)
+ {
+ double numericValue = Convert.ToDouble(value);
+ if (!string.IsNullOrEmpty(expression))
+ {
+ numericValue = SerinArithmeticExpressionEvaluator.Evaluate(expression, numericValue);
+ }
+
+ return numericValue;
+ }
+ }
+}
diff --git a/MyDll/MyDll.csproj b/MyDll/MyDll.csproj
index 72543ce..2946f7e 100644
--- a/MyDll/MyDll.csproj
+++ b/MyDll/MyDll.csproj
@@ -14,6 +14,10 @@
+
+
+
+
diff --git a/MyDll/test.cs b/MyDll/test.cs
new file mode 100644
index 0000000..ac269d7
--- /dev/null
+++ b/MyDll/test.cs
@@ -0,0 +1,46 @@
+using IoTClient.Clients.PLC;
+using IoTClient.Common.Enums;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MyDll
+{
+ internal class test
+ {
+ private void T()
+ {
+ SiemensClient client = new SiemensClient(SiemensVersion.S7_200Smart, "127.0.0.1", 102);
+
+ //2、写操作
+ client.Write("Q1.3", true);
+ client.Write("V2205", (short)11);
+ client.Write("V2209", 33);
+ client.Write("V2305", "orderCode"); //写入字符串
+
+ //3、读操作
+ var value1 = client.ReadBoolean("Q1.3").Value;
+ var value2 = client.ReadInt16("V2205").Value;
+ var value3 = client.ReadInt32("V2209").Value;
+ var value4 = client.ReadString("V2305").Value; //读取字符串
+
+ //4、如果没有主动Open,则会每次读写操作的时候自动打开自动和关闭连接,这样会使读写效率大大减低。所以建议手动Open和Close。
+ client.Open();
+
+ //5、读写操作都会返回操作结果对象Result
+ var result = client.ReadInt16("V2205");
+ //5.1 读取是否成功(true或false)
+ var isSucceed = result.IsSucceed;
+ //5.2 读取失败的异常信息
+ var errMsg = result.Err;
+ //5.3 读取操作实际发送的请求报文
+ var requst = result.Requst;
+ //5.4 读取操作服务端响应的报文
+ var response = result.Response;
+ //5.5 读取到的值
+ var value = result.Value;
+ }
+ }
+}
diff --git a/NodeFlow/Model/SingleConditionNode.cs b/NodeFlow/Model/SingleConditionNode.cs
index 942b25c..9bb4727 100644
--- a/NodeFlow/Model/SingleConditionNode.cs
+++ b/NodeFlow/Model/SingleConditionNode.cs
@@ -1,4 +1,5 @@
-using Serein.NodeFlow.SerinExpression;
+
+using Serein.Library.SerinExpression;
namespace Serein.NodeFlow.Model
{
diff --git a/NodeFlow/Model/SingleExpOpNode.cs b/NodeFlow/Model/SingleExpOpNode.cs
index 6a3e3a3..041a7e1 100644
--- a/NodeFlow/Model/SingleExpOpNode.cs
+++ b/NodeFlow/Model/SingleExpOpNode.cs
@@ -1,5 +1,5 @@
-using Serein.NodeFlow;
-using Serein.NodeFlow.SerinExpression;
+using Serein.Library.SerinExpression;
+using Serein.NodeFlow;
using System;
using System.Collections.Generic;
using System.Linq;
diff --git a/NodeFlow/Serein.NodeFlow.csproj b/NodeFlow/Serein.NodeFlow.csproj
index b8eb682..8a2939e 100644
--- a/NodeFlow/Serein.NodeFlow.csproj
+++ b/NodeFlow/Serein.NodeFlow.csproj
@@ -9,8 +9,11 @@
+
+
+
diff --git a/WorkBench/MainWindow.xaml.cs b/WorkBench/MainWindow.xaml.cs
index 22282c6..14e24d2 100644
--- a/WorkBench/MainWindow.xaml.cs
+++ b/WorkBench/MainWindow.xaml.cs
@@ -25,7 +25,9 @@ using static Serein.WorkBench.MainWindow;
namespace Serein.WorkBench
{
-
+ ///
+ /// 拖拽创建节点类型
+ ///
public static class MouseNodeType
{
public static string RegionType { get; } = nameof(RegionType);
@@ -1997,10 +1999,6 @@ namespace Serein.WorkBench
return Uri.UnescapeDataString(relativeUri.ToString().Replace('/', System.IO.Path.DirectorySeparatorChar));
}
-
-
-
-
#region 创建两个控件之间的连接关系,在UI层面上显示为 带箭头指向的贝塞尔曲线
@@ -2251,7 +2249,7 @@ namespace Serein.WorkBench
}
else if (localhost == Localhost.Right)
{
- centerPoint.X += halfWidth;
+ centerPoint.X -= -halfWidth;
centerPoint.Y -= direction.Y / Math.Abs(direction.X) * halfHeight - margin;
}
else if (localhost == Localhost.Top)
@@ -2261,7 +2259,7 @@ namespace Serein.WorkBench
}
else if (localhost == Localhost.Bottom)
{
- centerPoint.Y += halfHeight;
+ centerPoint.Y -= -halfHeight;
centerPoint.X -= direction.X / Math.Abs(direction.Y) * halfWidth - margin;
}
diff --git a/WorkBench/Node/View/ActionNodeControl.xaml b/WorkBench/Node/View/ActionNodeControl.xaml
index 13ca862..6c968fe 100644
--- a/WorkBench/Node/View/ActionNodeControl.xaml
+++ b/WorkBench/Node/View/ActionNodeControl.xaml
@@ -22,7 +22,7 @@
-
+