C3031
2026-01-30 130802fa7ef10857db12f784956d5ea122a1eeb4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Linq.Expressions;
using System.Reflection;
using System.Collections.Concurrent;
using System.Diagnostics;
using LB_VisionProcesses;
 
namespace LB_SmartVision.ProcessRun
{
    public class ExpressionTreeMappingEngine
    {
        private ConcurrentDictionary<string, List<Action<IProcess>>> _compiledMappings;
        private readonly ConcurrentDictionary<string, IProcess> _processContext;
 
        public ExpressionTreeMappingEngine(ConcurrentDictionary<string, IProcess> processContext)
        {
            _processContext = processContext;
            _compiledMappings = new ConcurrentDictionary<string, List<Action<IProcess>>>();
        }
 
        public void CompileMappings(ConcurrentDictionary<string, List<Tuple<string, string>>> dicInputsMapping)
        {
            foreach (var processMapping in dicInputsMapping)
            {
                var processName = processMapping.Key;
                var actions = new List<Action<IProcess>>();
 
                foreach (var tuple in processMapping.Value)
                {
                    if (string.IsNullOrEmpty(tuple.Item2?.Trim()))
                        continue;
 
                    var action = CreateMappingAction(tuple.Item1, tuple.Item2);
                    if (action != null)
                        actions.Add(action);
                }
 
                _compiledMappings[processName] = actions;
            }
        }
 
        private Action<IProcess> CreateMappingAction(string inputPath, string outputPath)
        {
            try
            {
                // 解析输入路径:TargetProcess.InputType.InputProperty
                var inputParts = inputPath.Split('.');
                if (inputParts.Length < 3) return null;
 
                string targetProcessName = inputParts[0];
                string inputType = inputParts[1]; // 通常是 "Inputs"
                string inputProperty = inputParts[2];
 
                // 解析输出路径:SourceProcess.OutputType.OutputProperty
                var outputParts = outputPath.Split('.');
                if (outputParts.Length < 2) return null;
 
                string sourceProcessName = outputParts[0];
                string outputType = outputParts[1]; // "Inputs" 或 "Outputs"
                string outputProperty = outputParts.Length == 3 ? outputParts[2] : "";
 
                // 创建表达式参数
                var targetParameter = Expression.Parameter(typeof(IProcess), "targetProcess");
 
                // 构建获取源值的表达式
                var sourceValueExpression = BuildSourceValueExpression(sourceProcessName, outputType, outputProperty);
                if (sourceValueExpression == null) return null;
 
                // 构建设置目标值的表达式
                var setTargetExpression = BuildSetTargetExpression(targetParameter, inputType, inputProperty, sourceValueExpression);
                if (setTargetExpression == null) return null;
 
                // 编译为委托
                var lambda = Expression.Lambda<Action<IProcess>>(setTargetExpression, targetParameter);
                return lambda.Compile();
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"创建映射动作失败: {ex.Message}");
                return null;
            }
        }
 
        private Expression BuildSourceValueExpression(string sourceProcessName, string outputType, string outputProperty)
        {
            // 获取源流程实例:_processContext[sourceProcessName]
            var contextField = Expression.Constant(_processContext);
            var processNameConstant = Expression.Constant(sourceProcessName);
            var getItemMethod = typeof(ConcurrentDictionary<string, IProcess>).GetMethod("get_Item");
            var getProcessExpr = Expression.Call(contextField, getItemMethod, processNameConstant);
 
            // 转换为 IProcess
            var convertExpr = Expression.Convert(getProcessExpr, typeof(IProcess));
 
            // 添加 null 检查
            var nullCheck = Expression.NotEqual(convertExpr, Expression.Constant(null, typeof(IProcess)));
 
            // 根据输出类型和属性构建获取值的表达式
            Expression valueExpression = outputType switch
            {
                "Inputs" => BuildInputsValueExpression(convertExpr, outputProperty),
                "Outputs" => BuildOutputsValueExpression(convertExpr, outputProperty),
                _ => Expression.Constant(null, typeof(object))
            };
 
            // 如果源流程为 null,返回 null,否则返回值
            return Expression.Condition(nullCheck, valueExpression, Expression.Constant(null, typeof(object)));
        }
 
        private Expression BuildInputsValueExpression(Expression processExpr, string propertyName)
        {
            if (propertyName == "Image")
            {
                // 首先尝试字段,然后尝试属性
                return GetMemberExpression(processExpr, "InputImage");
            }
            else
            {
                return BuildInputsConcurrentDictionaryExpression(processExpr, propertyName);
            }
        }
 
        private Expression BuildOutputsValueExpression(Expression processExpr, string propertyName)
        {
            if (propertyName == "Image")
            {
                // 首先尝试字段,然后尝试属性
                return GetMemberExpression(processExpr, "OutputImage");
            }
            else if (propertyName == "Result")
            {
                // 首先尝试字段,然后尝试属性
                return GetMemberExpression(processExpr, "Result");
            }
            else if (propertyName == "Fixture")
            {
                // 通过 Params 获取 Fixture
                var paramsExpr = GetMemberExpression(processExpr, "Params");
                return GetMemberExpression(paramsExpr, "Fixture");
            }
            else
            {
                return BuildOutputsConcurrentDictionaryExpression(processExpr, propertyName);
            }
        }
 
        private Expression BuildInputsConcurrentDictionaryExpression(Expression processExpr, string propertyName)
        {
            // process.Params.Inputs[propertyName]
            var paramsExpr = GetMemberExpression(processExpr, "Params");
            var inputsExpr = GetMemberExpression(paramsExpr, "Inputs");
 
            var indexer = inputsExpr.Type.GetProperty("Item", new[] { typeof(string) });
            if (indexer == null)
                throw new InvalidOperationException("Inputs 类型没有字符串索引器");
 
            var propertyNameConstant = Expression.Constant(propertyName);
            return Expression.Property(inputsExpr, indexer, propertyNameConstant);
        }
 
        private Expression BuildOutputsConcurrentDictionaryExpression(Expression processExpr, string propertyName)
        {
            // process.Params.Outputs[propertyName]
            var paramsExpr = GetMemberExpression(processExpr, "Params");
            var outputsExpr = GetMemberExpression(paramsExpr, "Outputs");
 
            var indexer = outputsExpr.Type.GetProperty("Item", new[] { typeof(string) });
            if (indexer == null)
                throw new InvalidOperationException("Outputs 类型没有字符串索引器");
 
            var propertyNameConstant = Expression.Constant(propertyName);
            return Expression.Property(outputsExpr, indexer, propertyNameConstant);
        }
 
        /// <summary>
        /// 通用的成员访问方法:首先尝试字段,然后尝试属性
        /// </summary>
        private Expression GetMemberExpression(Expression instance, string memberName)
        {
            var type = instance.Type;
 
            // 首先尝试字段
            var field = type.GetField(memberName, BindingFlags.Public | BindingFlags.Instance);
            if (field != null)
            {
                return Expression.Field(instance, field);
            }
 
            // 然后尝试属性
            var property = type.GetProperty(memberName, BindingFlags.Public | BindingFlags.Instance);
            if (property != null)
            {
                return Expression.Property(instance, property);
            }
 
            throw new InvalidOperationException($"在类型 {type.Name} 中找不到字段或属性: {memberName}");
        }
 
        private Expression BuildSetTargetExpression(ParameterExpression targetParameter, string inputType, string inputProperty, Expression sourceValueExpression)
        {
            return inputProperty switch
            {
                "Image" => BuildSetImageExpression(targetParameter, sourceValueExpression),
                "Fixture" => BuildSetFixtureExpression(targetParameter, sourceValueExpression),
                "Result" => BuildSetResultExpression(targetParameter, inputProperty, sourceValueExpression),
                _ => BuildSetInputExpression(targetParameter, inputProperty, sourceValueExpression)
            };
        }
 
        private Expression BuildSetImageExpression(ParameterExpression target, Expression sourceValue)
        {
            // target.InputImage = sourceValue
            var inputImageExpr = GetMemberExpression(target, "InputImage");
            return Expression.Assign(inputImageExpr, Expression.Convert(sourceValue, inputImageExpr.Type));
        }
 
        private Expression BuildSetFixtureExpression(ParameterExpression target, Expression sourceValue)
        {
            //// target.Params.Fixture = sourceValue ?? new Fixture()
            //var paramsExpr = GetMemberExpression(target, "Params");
            //var fixtureExpr = GetMemberExpression(paramsExpr, "Fixture");
 
            //// 如果源值为null,创建新的Fixture
            //var newFixtureExpr = Expression.New(typeof(Fixture));
            //var coalesceExpr = Expression.Coalesce(
            //    Expression.Convert(sourceValue, typeof(Fixture)),
            //    newFixtureExpr
            //);
 
            //return Expression.Assign(fixtureExpr, coalesceExpr);
 
            // 如果源值为null,就设置为null,不创建新对象
            var paramsExpr = GetMemberExpression(target, "Params");
            var fixtureExpr = GetMemberExpression(paramsExpr, "Fixture");
 
            var convertedSourceValue = Expression.Convert(sourceValue, typeof(Fixture));
            return Expression.Assign(fixtureExpr, convertedSourceValue);
        }
 
        private Expression BuildSetResultExpression(ParameterExpression target, string propertyName, Expression sourceValue)
        {
            // target.Params.Inputs[propertyName] = sourceValue
            var paramsExpr = GetMemberExpression(target, "Params");
            var inputsExpr = GetMemberExpression(paramsExpr, "Inputs");
 
            var indexer = inputsExpr.Type.GetProperty("Item", new[] { typeof(string) });
            if (indexer == null)
                return Expression.Empty();
 
            var propertyNameConstant = Expression.Constant(propertyName);
            var targetIndexExpr = Expression.Property(inputsExpr, indexer, propertyNameConstant);
 
            return Expression.Assign(targetIndexExpr, Expression.Convert(sourceValue, targetIndexExpr.Type));
        }
 
        private Expression BuildSetInputExpression(ParameterExpression target, string propertyName, Expression sourceValue)
        {
            // 检查字典是否包含该键,如果包含则赋值
            var paramsExpr = GetMemberExpression(target, "Params");
            var inputsExpr = GetMemberExpression(paramsExpr, "Inputs");
 
            var containsMethod = inputsExpr.Type.GetMethod("Contains", new[] { typeof(string) });
            if (containsMethod == null)
                return Expression.Empty();
 
            var propertyNameConstant = Expression.Constant(propertyName);
            var containsCall = Expression.Call(inputsExpr, containsMethod, propertyNameConstant);
 
            // 如果包含键,则赋值
            var indexer = inputsExpr.Type.GetProperty("Item", new[] { typeof(string) });
            if (indexer == null)
                return Expression.Empty();
 
            var targetIndexExpr = Expression.Property(inputsExpr, indexer, propertyNameConstant);
            var assignExpr = Expression.Assign(
                targetIndexExpr,
                Expression.Convert(sourceValue, targetIndexExpr.Type)
            );
 
            // 条件表达式:if (inputs.Contains(propertyName)) { inputs[propertyName] = sourceValue; }
            return Expression.IfThen(containsCall, assignExpr);
        }
 
        public void UpdateInputs(IProcess process)
        {
            if (_compiledMappings.TryGetValue(process.strProcessName, out var actions))
            {
                foreach (var action in actions)
                {
                    try
                    {
                        action(process);
                    }
                    catch (Exception ex)
                    {
                        // 处理运行时异常
                        Debug.WriteLine($"执行映射动作失败: {ex.Message}");
                    }
                }
            }
        }
 
        public void Dispose()
        {
            foreach (var list in _compiledMappings.Values)
            {
                list.Clear();
            }
            _compiledMappings.Clear();
        }
 
        public void ClearMappings()
        {
            _compiledMappings.Clear();
        }
 
        public void RemoveProcessMappings(string processName)
        {
            _compiledMappings.TryRemove(processName, out _);
        }
    }
 
    // 辅助扩展方法,用于调试
    public static class ExpressionTreeDebugExtensions
    {
        public static void DebugMemberAccess(this ExpressionTreeMappingEngine engine, IProcess testProcess)
        {
            var processType = typeof(IProcess);
 
            Debug.WriteLine("=== IProcess 成员调试信息 ===");
            Debug.WriteLine("字段:");
            foreach (var field in processType.GetFields(BindingFlags.Public | BindingFlags.Instance))
            {
                Debug.WriteLine($"  {field.Name} : {field.FieldType.Name}");
            }
 
            Debug.WriteLine("属性:");
            foreach (var prop in processType.GetProperties(BindingFlags.Public | BindingFlags.Instance))
            {
                Debug.WriteLine($"  {prop.Name} : {prop.PropertyType.Name}");
            }
 
            // 测试具体成员访问
            try
            {
                var processExpr = Expression.Parameter(typeof(IProcess), "p");
                var outputImageExpr = Expression.Field(processExpr, "OutputImage");
                var lambda = Expression.Lambda<Func<IProcess, object>>(outputImageExpr, processExpr).Compile();
                var result = lambda(testProcess);
                Debug.WriteLine($"OutputImage 字段访问成功: {result ?? "null"}");
            }
            catch (Exception ex)
            {
                Debug.WriteLine($"OutputImage 字段访问失败: {ex.Message}");
            }
        }
    }
}