示例工程版本提升至net462,项目添加了部分空引用检测逻辑。累了,消不完的空引用警告(T.T)

This commit is contained in:
fengjiayi
2024-09-30 22:20:02 +08:00
parent 8ecbdfa7a6
commit e4aa3b6185
45 changed files with 562 additions and 581 deletions

View File

@@ -41,12 +41,12 @@ namespace Serein.NodeFlow.Base
/// <summary>
/// 节点guid
/// </summary>
public string Guid { get; set; }
public string Guid { get; set; } = string.Empty;
/// <summary>
/// 显示名称
/// </summary>
public string DisplayName { get; set; }
public string DisplayName { get; set; } = string.Empty;
/// <summary>
/// 是否为起点控件
@@ -76,7 +76,7 @@ namespace Serein.NodeFlow.Base
/// <summary>
/// 运行时的异常信息(仅在 FlowState 为 Error 时存在对应值)
/// </summary>
public Exception RuningException { get; set; } = null;
public Exception? RuningException { get; set; } = null;
/// <summary>

View File

@@ -74,17 +74,17 @@ namespace Serein.NodeFlow.Base
internal virtual NodeModelBase LoadInfo(NodeInfo nodeInfo)
{
var node = this;
if (node != null)
this.Guid = nodeInfo.Guid;
if(this.MethodDetails is not null)
{
node.Guid = nodeInfo.Guid;
for (int i = 0; i < nodeInfo.ParameterData.Length; i++)
{
Parameterdata? pd = nodeInfo.ParameterData[i];
node.MethodDetails.ExplicitDatas[i].IsExplicitData = pd.State;
node.MethodDetails.ExplicitDatas[i].DataValue = pd.Value;
this.MethodDetails.ExplicitDatas[i].IsExplicitData = pd.State;
this.MethodDetails.ExplicitDatas[i].DataValue = pd.Value;
}
}
return this;
}
@@ -132,7 +132,7 @@ namespace Serein.NodeFlow.Base
if (upstreamNodes[i].DebugSetting.InterruptClass != InterruptClass.None) // 执行触发前
{
var cancelType = await upstreamNodes[i].DebugSetting.GetInterruptTask();
await Console.Out.WriteLineAsync($"[{upstreamNodes[i].MethodDetails.MethodName}]中断已{cancelType},开始执行后继分支");
await Console.Out.WriteLineAsync($"[{upstreamNodes[i]?.MethodDetails?.MethodName}]中断已{cancelType},开始执行后继分支");
}
upstreamNodes[i].PreviousNode = currentNode;
await upstreamNodes[i].StartExecute(context); // 执行流程节点的上游分支
@@ -165,7 +165,7 @@ namespace Serein.NodeFlow.Base
if (nextNodes[i].DebugSetting.InterruptClass != InterruptClass.None) // 执行触发前
{
var cancelType = await nextNodes[i].DebugSetting.GetInterruptTask();
await Console.Out.WriteLineAsync($"[{nextNodes[i].MethodDetails.MethodName}]中断已{cancelType},开始执行后继分支");
await Console.Out.WriteLineAsync($"[{nextNodes[i]?.MethodDetails?.MethodName}]中断已{cancelType},开始执行后继分支");
}
nextNodes[i].PreviousNode = currentNode;
stack.Push(nextNodes[i]);
@@ -194,18 +194,22 @@ namespace Serein.NodeFlow.Base
// this.NextOrientation = ConnectionType.None;
// return null;
//}
await Console.Out.WriteLineAsync($"[{this.MethodDetails.MethodName}]中断已{cancelType},开始执行后继分支");
await Console.Out.WriteLineAsync($"[{this.MethodDetails?.MethodName}]中断已{cancelType},开始执行后继分支");
}
#endregion
MethodDetails md = MethodDetails;
MethodDetails? md = MethodDetails;
//var del = md.MethodDelegate.Clone();
if (md is null)
{
throw new Exception($"节点{this.Guid}不存在方法信息请检查是否需要重写节点的ExecutingAsync");
}
if (!context.Env.TryGetDelegate(md.MethodName, out var del))
{
throw new Exception("不存在对应委托");
throw new Exception($"节点{this.Guid}不存在对应委托");
}
md.ActingInstance ??= context.Env.IOC.Get(MethodDetails.ActingInstanceType);
md.ActingInstance ??= context.Env.IOC.Get(md.ActingInstanceType);
object instance = md.ActingInstance;
var haveParameter = md.ExplicitDatas.Length > 0;
@@ -281,7 +285,7 @@ namespace Serein.NodeFlow.Base
if (ed.IsExplicitData) // 判断是否使用显示的输入参数
{
if (ed.DataValue.StartsWith("@get", StringComparison.OrdinalIgnoreCase))
if (ed.DataValue.StartsWith("@get", StringComparison.OrdinalIgnoreCase) && flowData is not null)
{
// 执行表达式从上一节点获取对象
inputParameter = SerinExpressionEvaluator.Evaluate(ed.DataValue, flowData, out _);
@@ -315,8 +319,6 @@ namespace Serein.NodeFlow.Base
}
}
//var attribute = ed.DataType.GetCustomAttribute<EnumTypeConvertorAttribute>();
//if (attribute is not null && attribute.EnumType.IsEnum) // 获取枚举转换器中记录的枚举
if ( ed.DataType != ed.ExplicitType) // 获取枚举转换器中记录的枚举
{
if (ed.ExplicitType.IsEnum && Enum.TryParse(ed.ExplicitType, ed.DataValue, out var resultEnum)) // 获取对应的枚举项
@@ -339,41 +341,43 @@ namespace Serein.NodeFlow.Base
try
{
string? valueStr = inputParameter?.ToString();
parameters[i] = ed.DataType switch
{
//Type t when t == previousDataType => inputParameter, // 上下文
Type t when t.IsEnum => Enum.Parse(ed.DataType, ed.DataValue),// 需要枚举
Type t when t == typeof(IDynamicContext) => context, // 上下文
Type t when t.IsEnum => Enum.Parse(ed.DataType, ed.DataValue),// 需要枚举
Type t when t == typeof(string) => inputParameter?.ToString(),
Type t when t == typeof(char) && !string.IsNullOrEmpty(valueStr) => char.Parse(valueStr),
Type t when t == typeof(bool) && !string.IsNullOrEmpty(valueStr) => inputParameter is not null && bool.Parse(valueStr),
Type t when t == typeof(float) && !string.IsNullOrEmpty(valueStr) => float.Parse(valueStr),
Type t when t == typeof(decimal) && !string.IsNullOrEmpty(valueStr) => decimal.Parse(valueStr),
Type t when t == typeof(double) && !string.IsNullOrEmpty(valueStr) => double.Parse(valueStr),
Type t when t == typeof(sbyte) && !string.IsNullOrEmpty(valueStr) => sbyte.Parse(valueStr),
Type t when t == typeof(byte) && !string.IsNullOrEmpty(valueStr) => byte.Parse(valueStr),
Type t when t == typeof(short) && !string.IsNullOrEmpty(valueStr) => short.Parse(valueStr),
Type t when t == typeof(ushort) && !string.IsNullOrEmpty(valueStr) => ushort.Parse(valueStr),
Type t when t == typeof(int) && !string.IsNullOrEmpty(valueStr) => int.Parse(valueStr),
Type t when t == typeof(uint) && !string.IsNullOrEmpty(valueStr) => uint.Parse(valueStr),
Type t when t == typeof(long) && !string.IsNullOrEmpty(valueStr) => long.Parse(valueStr),
Type t when t == typeof(ulong) && !string.IsNullOrEmpty(valueStr) => ulong.Parse(valueStr),
Type t when t == typeof(nint) && !string.IsNullOrEmpty(valueStr) => nint.Parse(valueStr),
Type t when t == typeof(nuint) && !string.IsNullOrEmpty(valueStr) => nuint.Parse(valueStr),
//Type t when t == typeof(DateTime) => string.IsNullOrEmpty(valueStr) ? 0 : DateTime.Parse(valueStr),
Type t when t == typeof(MethodDetails) => md, // 节点方法描述
Type t when t == typeof(NodeModelBase) => nodeModel, // 节点实体类
Type t when t == typeof(Guid) => new Guid(inputParameter?.ToString()),
Type t when t == typeof(DateTime) => DateTime.Parse(inputParameter?.ToString()),
Type t when t == typeof(string) => inputParameter?.ToString(),
Type t when t == typeof(char) => char.Parse(inputParameter?.ToString()),
Type t when t == typeof(bool) => inputParameter is null ? false : bool.Parse(inputParameter?.ToString()),
Type t when t == typeof(float) => inputParameter is null ? 0F : float.Parse(inputParameter?.ToString()),
Type t when t == typeof(decimal) => inputParameter is null ? 0 : decimal.Parse(inputParameter?.ToString()),
Type t when t == typeof(double) => inputParameter is null ? 0 : double.Parse(inputParameter?.ToString()),
Type t when t == typeof(sbyte) => inputParameter is null ? 0 : sbyte.Parse(inputParameter?.ToString()),
Type t when t == typeof(byte) => inputParameter is null ? 0 : byte.Parse(inputParameter?.ToString()),
Type t when t == typeof(short) => inputParameter is null ? 0 : short.Parse(inputParameter?.ToString()),
Type t when t == typeof(ushort) => inputParameter is null ? 0U : ushort.Parse(inputParameter?.ToString()),
Type t when t == typeof(int) => inputParameter is null ? 0 : int.Parse(inputParameter?.ToString()),
Type t when t == typeof(uint) => inputParameter is null ? 0U : uint.Parse(inputParameter?.ToString()),
Type t when t == typeof(long) => inputParameter is null ? 0L : long.Parse(inputParameter?.ToString()),
Type t when t == typeof(ulong) => inputParameter is null ? 0UL : ulong.Parse(inputParameter?.ToString()),
Type t when t == typeof(nint) => inputParameter is null ? 0 : nint.Parse(inputParameter?.ToString()),
Type t when t == typeof(nuint) => inputParameter is null ? 0 : nuint.Parse(inputParameter?.ToString()),
Type t when t.IsArray => (inputParameter as Array)?.Cast<object>().ToList(),
Type t when t.IsGenericType && t.GetGenericTypeDefinition() == typeof(List<>) => inputParameter,
Type t when Nullable.GetUnderlyingType(t) != null => inputParameter is null ? null : Convert.ChangeType(inputParameter, Nullable.GetUnderlyingType(t)),
_ => inputParameter,
// Type t when Nullable.GetUnderlyingType(t) != null => inputParameter is null ? null : Convert.ChangeType(inputParameter, Nullable.GetUnderlyingType(t)),
};
}
catch (Exception ex) // 节点参数类型转换异常
{
parameters[i] = null;
parameters[i] = new object();
Console.WriteLine(ex);
}
}
@@ -395,21 +399,25 @@ namespace Serein.NodeFlow.Base
}
}
private static async Task MonitorObjExpInterrupt(IDynamicContext context, NodeModelBase nodeModel, object data, int type)
private static async Task MonitorObjExpInterrupt(IDynamicContext context, NodeModelBase nodeModel, object? data, int monitorType)
{
MonitorObjectEventArgs.ObjSourceType sourceType;
string key;
if(type == 0)
string? key;
if(monitorType == 0)
{
key = data.GetType().FullName;
key = data?.GetType()?.FullName;
sourceType = MonitorObjectEventArgs.ObjSourceType.IOCObj;
}
else
{
key = nodeModel.Guid;
sourceType = MonitorObjectEventArgs.ObjSourceType.IOCObj;
}
if (string.IsNullOrEmpty(key))
{
return;
}
if (context.Env.CheckObjMonitorState(key, out List<string> exps)) // 如果新的数据处于查看状态通知UI进行更新交给运行环境判断
{
context.Env.MonitorObjectNotification(nodeModel.Guid, data, sourceType); // 对象处于监视状态通知UI更新数据显示

View File

@@ -46,7 +46,7 @@ namespace Serein.NodeFlow
public FlowEnvironment()
{
sereinIOC = new SereinIOC();
//ChannelFlowInterrupt = new ChannelFlowInterrupt();
ChannelFlowInterrupt = new ChannelFlowInterrupt();
//LoadedAssemblyPaths = new List<string>();
//LoadedAssemblies = new List<Assembly>();
//MethodDetailss = new List<MethodDetails>();
@@ -69,67 +69,67 @@ namespace Serein.NodeFlow
/// <summary>
/// 加载Dll
/// </summary>
public event LoadDllHandler OnDllLoad;
public event LoadDllHandler? OnDllLoad;
/// <summary>
/// 移除DLL
/// </summary>
public event RemoteDllHandler OnDllRemote;
public event RemoteDllHandler? OnDllRemote;
/// <summary>
/// 项目加载完成
/// </summary>
public event ProjectLoadedHandler OnProjectLoaded;
public event ProjectLoadedHandler? OnProjectLoaded;
/// <summary>
/// 节点连接属性改变事件
/// </summary>
public event NodeConnectChangeHandler OnNodeConnectChange;
public event NodeConnectChangeHandler? OnNodeConnectChange;
/// <summary>
/// 节点创建事件
/// </summary>
public event NodeCreateHandler OnNodeCreate;
public event NodeCreateHandler? OnNodeCreate;
/// <summary>
/// 移除节点事件
/// </summary>
public event NodeRemoteHandler OnNodeRemote;
public event NodeRemoteHandler? OnNodeRemote;
/// <summary>
/// 起始节点变化事件
/// </summary>
public event StartNodeChangeHandler OnStartNodeChange;
public event StartNodeChangeHandler? OnStartNodeChange;
/// <summary>
/// 流程运行完成事件
/// </summary>
public event FlowRunCompleteHandler OnFlowRunComplete;
public event FlowRunCompleteHandler? OnFlowRunComplete;
/// <summary>
/// 被监视的对象改变事件
/// </summary>
public event MonitorObjectChangeHandler OnMonitorObjectChange;
public event MonitorObjectChangeHandler? OnMonitorObjectChange;
/// <summary>
/// 节点中断状态改变事件
/// </summary>
public event NodeInterruptStateChangeHandler OnNodeInterruptStateChange;
public event NodeInterruptStateChangeHandler? OnNodeInterruptStateChange;
/// <summary>
/// 节点触发了中断
/// </summary>
public event ExpInterruptTriggerHandler OnInterruptTrigger;
public event ExpInterruptTriggerHandler? OnInterruptTrigger;
/// <summary>
/// 容器改变
/// </summary>
public event IOCMembersChangedHandler OnIOCMembersChanged;
public event IOCMembersChangedHandler? OnIOCMembersChanged;
/// <summary>
/// 节点需要定位
/// </summary>
public event NodeLocatedHandler OnNodeLocate;
public event NodeLocatedHandler? OnNodeLocate;
#endregion
#region
@@ -196,12 +196,12 @@ namespace Serein.NodeFlow
/// <summary>
/// 起始节点私有属性
/// </summary>
private NodeModelBase _startNode;
private NodeModelBase? _startNode = null;
/// <summary>
/// 起始节点
/// </summary>
private NodeModelBase StartNode
private NodeModelBase? StartNode
{
get
{
@@ -209,6 +209,10 @@ namespace Serein.NodeFlow
}
set
{
if (value is null)
{
return;
}
if (_startNode is not null)
{
_startNode.IsStart = false;
@@ -481,17 +485,19 @@ namespace Serein.NodeFlow
public bool RemoteDll(string assemblyFullName)
{
var library = NodeLibrarys.FirstOrDefault(nl => nl.Assembly.FullName.Equals(assemblyFullName));
var library = NodeLibrarys.FirstOrDefault(nl => assemblyFullName.Equals(nl.Assembly.FullName));
if(library is null)
{
return false;
}
var nodes = Nodes.Values.ToDictionary(
key => key.MethodDetails.MethodName,
value => value
);
if(nodes.Count == 0)
var groupedNodes = Nodes.Values
.Where(node => node.MethodDetails is not null)
.ToArray()
.GroupBy(node => node.MethodDetails!.MethodName)
.ToDictionary(
key => key.Key,
group => group.Count());
if(Nodes.Count == 0)
{
return true; // 当前无节点,可以直接删除
}
@@ -500,9 +506,12 @@ namespace Serein.NodeFlow
{
foreach(var md in mds)
{
if (nodes.ContainsKey(md.MethodName))
if(groupedNodes.TryGetValue(md.MethodName,out int count))
{
return false; // 创建过相关的节点
if (count > 0)
{
return false; // 创建过相关的节点
}
}
}
MethodDetailss.Remove(library);
@@ -510,7 +519,7 @@ namespace Serein.NodeFlow
}
else
{
return true;
return true;
}
}
@@ -685,9 +694,10 @@ namespace Serein.NodeFlow
}
}
public bool TryGetDelegate(string methodName, out Delegate del)
public bool TryGetDelegate(string methodName, out Delegate? del)
{
if (MethodDelegates.TryGetValue(methodName, out del))
if (!string.IsNullOrEmpty(methodName) && MethodDelegates.TryGetValue(methodName, out del))
{
return del != null;
}
@@ -742,7 +752,7 @@ namespace Serein.NodeFlow
return false;
}
nodeModel.DebugSetting.InterruptClass = interruptClass;
OnNodeInterruptStateChange.Invoke(new NodeInterruptStateChangeEventArgs(nodeGuid, interruptClass));
OnNodeInterruptStateChange?.Invoke(new NodeInterruptStateChangeEventArgs(nodeGuid, interruptClass));
return true;
}
@@ -958,11 +968,19 @@ namespace Serein.NodeFlow
{
// 加载DLL创建 MethodDetails、实例作用对象、委托方法
var assemblyName = type.Assembly.GetName().Name;
if (string.IsNullOrEmpty(assemblyName))
{
continue;
}
var methods = MethodDetailsHelperTmp.GetMethodsToProcess(type);
foreach(var method in methods)
{
(var md, var del) = MethodDetailsHelperTmp.CreateMethodDetails(type, method, assemblyName);
if(md is null || del is null)
{
Console.WriteLine($"无法加载方法信息:{assemblyName}-{type}-{method}");
continue;
}
if (MethodDelegates.TryAdd(md.MethodName, del))
{
methodDetails.Add(md);

View File

@@ -30,7 +30,7 @@ namespace Serein.NodeFlow.Model
{
return [];
}
internal override NodeInfo ToInfo()
internal override NodeInfo? ToInfo()
{
if (MethodDetails is null) return null;

View File

@@ -52,7 +52,7 @@ public static class MethodDetailsHelperTmp
/// 创建方法信息
/// </summary>
/// <returns></returns>
public static (MethodDetails,Delegate) CreateMethodDetails(Type type, MethodInfo method, string assemblyName)
public static (MethodDetails?,Delegate?) CreateMethodDetails(Type type, MethodInfo method, string assemblyName)
{
var methodName = method.Name;

View File

@@ -1,13 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.Emit;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection;
using System.Reflection.Emit;
@@ -78,7 +69,7 @@ namespace Serein.NodeFlow.Tool
// 如果类型已经缓存,直接返回缓存的类型
if (typeCache.ContainsKey(typeName))
{
return Activator.CreateInstance(typeCache[typeName]);
return Activator.CreateInstance(typeCache[typeName])!;
}
// 定义动态程序集和模块
@@ -98,7 +89,7 @@ namespace Serein.NodeFlow.Tool
if (propValue is IList<Dictionary<string, object>>) // 处理数组类型
{
var nestedPropValue = (propValue as IList<Dictionary<string, object>>)[0];
var nestedPropValue = (propValue as IList<Dictionary<string, object>>)![0];
var nestedType = CreateObjectWithProperties(nestedPropValue, $"{propName}Element");
propType = nestedType.GetType().MakeArrayType(); // 创建数组类型
}
@@ -152,7 +143,7 @@ namespace Serein.NodeFlow.Tool
typeCache[typeName] = dynamicType;
// 创建对象实例
return Activator.CreateInstance(dynamicType);
return Activator.CreateInstance(dynamicType)!;
}
// 方法 2: 递归设置对象的属性值
@@ -169,10 +160,10 @@ namespace Serein.NodeFlow.Tool
if (value is Dictionary<string, object> nestedProperties)
{
// 创建嵌套对象
var nestedObj = Activator.CreateInstance(propInfo.PropertyType);
var nestedObj = Activator.CreateInstance(propInfo!.PropertyType);
// 递归设置嵌套对象的值
SetPropertyValues(nestedObj, nestedProperties);
SetPropertyValues(nestedObj!, nestedProperties);
// 将嵌套对象赋值给属性
propInfo.SetValue(obj, nestedObj);
@@ -180,7 +171,7 @@ namespace Serein.NodeFlow.Tool
else
{
// 直接赋值给属性
propInfo.SetValue(obj, value);
propInfo!.SetValue(obj, value);
}
}
}
@@ -222,7 +213,7 @@ namespace Serein.NodeFlow.Tool
if (propValue is Dictionary<string, object> nestedProperties)
{
var nestedObj = Activator.CreateInstance(propInfo.PropertyType);
if (SetPropertyValuesWithValidation(nestedObj, nestedProperties))
if (nestedObj is not null && SetPropertyValuesWithValidation(nestedObj, nestedProperties))
{
propInfo.SetValue(obj, nestedObj);
}
@@ -235,22 +226,24 @@ namespace Serein.NodeFlow.Tool
{
// 获取目标类型的数组元素类型
var elementType = propInfo.PropertyType.GetElementType();
var array = Array.CreateInstance(elementType, list.Count);
for (int i = 0; i < list.Count; i++)
if (elementType is not null)
{
var item = Activator.CreateInstance(elementType);
if (SetPropertyValuesWithValidation(item, list[i]))
{
array.SetValue(item, i);
}
else
{
allSuccessful = false; // 赋值失败
}
}
var array = Array.CreateInstance(elementType, list.Count);
propInfo.SetValue(obj, array);
for (int i = 0; i < list.Count; i++)
{
var item = Activator.CreateInstance(elementType);
if (item is not null && SetPropertyValuesWithValidation(item, list[i]))
{
array.SetValue(item, i);
}
else
{
allSuccessful = false; // 赋值失败
}
}
propInfo.SetValue(obj, array);
}
}
else
{

View File

@@ -39,7 +39,7 @@ namespace Serein.NodeFlow.Tool.SereinExpression.Resolver
return false;
}
private object GetMemberValue(object? obj, string memberPath)
private object? GetMemberValue(object? obj, string memberPath)
{
string[] members = memberPath[1..].Split('.');
foreach (var member in members)

View File

@@ -29,7 +29,7 @@ namespace Serein.NodeFlow.Tool.SereinExpression
}
}
public static SereinConditionResolver ConditionParse(object data, string expression)
public static SereinConditionResolver ConditionParse(object? data, string expression)
{
if (expression.StartsWith('.') || expression.StartsWith('<')) // 表达式前缀属于从上一个节点数据对象获取成员值
{
@@ -91,7 +91,7 @@ namespace Serein.NodeFlow.Tool.SereinExpression
/// <summary>
/// 解析对象表达式
/// </summary>
private static SereinConditionResolver ParseObjectExpression(object data, string expression)
private static SereinConditionResolver ParseObjectExpression(object? data, string expression)
{
var parts = expression.Split(' ');
string operatorStr = parts[0]; // 获取操作类型

View File

@@ -41,7 +41,7 @@ namespace Serein.NodeFlow.Tool.SereinExpression
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
/// <exception cref="NotSupportedException"></exception>
public static object Evaluate(string expression, object targetObJ, out bool isChange)
public static object? Evaluate(string expression, object targetObJ, out bool isChange)
{
var parts = expression.Split([' '], 2);
if (parts.Length != 2)
@@ -84,7 +84,7 @@ namespace Serein.NodeFlow.Tool.SereinExpression
/// <param name="methodCall">方法名称</param>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
private static object InvokeMethod(object target, string methodCall)
private static object? InvokeMethod(object target, string methodCall)
{
var methodParts = methodCall.Split(separator, StringSplitOptions.RemoveEmptyEntries);
if (methodParts.Length != 2)
@@ -98,12 +98,7 @@ namespace Serein.NodeFlow.Tool.SereinExpression
.Select(p => p.Trim())
.ToArray();
var method = target.GetType().GetMethod(methodName);
if (method is null)
{
throw new ArgumentException($"Method {methodName} not found on target.");
}
var method = target.GetType().GetMethod(methodName) ?? throw new ArgumentException($"Method {methodName} not found on target.");
var parameterValues = method.GetParameters()
.Select((p, index) => Convert.ChangeType(parameters[index], p.ParameterType))
.ToArray();
@@ -119,15 +114,14 @@ namespace Serein.NodeFlow.Tool.SereinExpression
/// <param name="memberPath">属性路径</param>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
private static object GetMember(object target, string memberPath)
private static object? GetMember(object? target, string memberPath)
{
if (target is null) return null;
// 分割成员路径,按 '.' 处理多级访问
var members = memberPath.Split('.');
foreach (var member in members)
{
if (target == null) return null;
// 检查成员是否包含数组索引,例如 "cars[0]"
var arrayIndexStart = member.IndexOf('[');
if (arrayIndexStart != -1)
@@ -148,22 +142,22 @@ namespace Serein.NodeFlow.Tool.SereinExpression
}
// 获取数组或集合对象
var arrayProperty = target.GetType().GetProperty(arrayName);
if (arrayProperty != null)
var arrayProperty = target?.GetType().GetProperty(arrayName);
if (arrayProperty is null)
{
target = arrayProperty.GetValue(target);
}
else
{
var arrayField = target.GetType().GetField(arrayName);
if (arrayField != null)
{
target = arrayField.GetValue(target);
}
else
var arrayField = target?.GetType().GetField(arrayName);
if (arrayField is null)
{
throw new ArgumentException($"Member {arrayName} not found on target.");
}
else
{
target = arrayField.GetValue(target);
}
}
else
{
target = arrayProperty.GetValue(target);
}
// 访问数组或集合中的指定索引
@@ -191,22 +185,22 @@ namespace Serein.NodeFlow.Tool.SereinExpression
else
{
// 处理非数组情况的属性或字段
var property = target.GetType().GetProperty(member);
if (property != null)
var property = target?.GetType().GetProperty(member);
if (property is null)
{
target = property.GetValue(target);
}
else
{
var field = target.GetType().GetField(member);
if (field != null)
{
target = field.GetValue(target);
}
else
var field = target?.GetType().GetField(member);
if (field is null)
{
throw new ArgumentException($"Member {member} not found on target.");
}
else
{
target = field.GetValue(target);
}
}
else
{
target = property.GetValue(target);
}
}
}
@@ -220,7 +214,7 @@ namespace Serein.NodeFlow.Tool.SereinExpression
/// <param name="assignment">属性路径 </param>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
private static object SetMember(object target, string assignment)
private static object? SetMember(object? target, string assignment)
{
var parts = assignment.Split(new[] { '=' }, 2);
if (parts.Length != 2)
@@ -238,7 +232,7 @@ namespace Serein.NodeFlow.Tool.SereinExpression
// 检查是否包含数组索引
var arrayIndexStart = member.IndexOf('[');
if (arrayIndexStart != -1)
if (arrayIndexStart != -1)
{
// 解析数组名和索引
var arrayName = member.Substring(0, arrayIndexStart);
@@ -255,24 +249,24 @@ namespace Serein.NodeFlow.Tool.SereinExpression
}
// 获取数组或集合
var arrayProperty = target.GetType().GetProperty(arrayName);
if (arrayProperty != null)
var arrayProperty = target?.GetType().GetProperty(arrayName);
if (arrayProperty is null)
{
target = arrayProperty.GetValue(target);
}
else
{
var arrayField = target.GetType().GetField(arrayName);
if (arrayField != null)
{
target = arrayField.GetValue(target);
}
else
var arrayField = target?.GetType().GetField(arrayName);
if (arrayField is null)
{
throw new ArgumentException($"Member {arrayName} not found on target.");
}
else
{
target = arrayField.GetValue(target);
}
}
else
{
target = arrayProperty.GetValue(target);
}
// 获取目标数组或集合中的指定元素
if (target is Array array)
@@ -299,46 +293,47 @@ namespace Serein.NodeFlow.Tool.SereinExpression
else
{
// 处理非数组情况的属性或字段
var property = target.GetType().GetProperty(member);
if (property != null)
var property = target?.GetType().GetProperty(member);
if (property is null)
{
target = property.GetValue(target);
}
else
{
var field = target.GetType().GetField(member);
if (field != null)
{
target = field.GetValue(target);
}
else
var field = target?.GetType().GetField(member);
if (field is null)
{
throw new ArgumentException($"Member {member} not found on target.");
}
else
{
target = field.GetValue(target);
}
}
else
{
target = property.GetValue(target);
}
}
}
// 设置值
var lastMember = members.Last();
var lastProperty = target.GetType().GetProperty(lastMember);
if (lastProperty != null)
var lastProperty = target?.GetType().GetProperty(lastMember);
if (lastProperty is null)
{
var convertedValue = Convert.ChangeType(value, lastProperty.PropertyType);
lastProperty.SetValue(target, convertedValue);
}
else
{
var lastField = target.GetType().GetField(lastMember);
if (lastField != null)
var lastField = target?.GetType().GetField(lastMember);
if (lastField is null)
{
throw new ArgumentException($"Member {lastMember} not found on target.");
}
else
{
var convertedValue = Convert.ChangeType(value, lastField.FieldType);
lastField.SetValue(target, convertedValue);
}
else
{
throw new ArgumentException($"Member {lastMember} not found on target.");
}
}
else
{
var convertedValue = Convert.ChangeType(value, lastProperty.PropertyType);
lastProperty.SetValue(target, convertedValue);
}
return target;