From 220e83ca0af3ae16d46884456864c9d4daf48eb0 Mon Sep 17 00:00:00 2001 From: ncguilbeault Date: Thu, 13 Aug 2026 09:20:39 +0100 Subject: [PATCH 1/2] Refactor EnumerateTypeHierarchy for nested type traversal --- .../ParsingConfigHelper.cs | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/Bonsai.Scripting.Expressions/ParsingConfigHelper.cs b/src/Bonsai.Scripting.Expressions/ParsingConfigHelper.cs index 0929d2e..5dbbecb 100644 --- a/src/Bonsai.Scripting.Expressions/ParsingConfigHelper.cs +++ b/src/Bonsai.Scripting.Expressions/ParsingConfigHelper.cs @@ -24,16 +24,25 @@ static IDynamicLinqCustomTypeProvider CreateCustomTypeProvider(ParsingConfig con static IEnumerable EnumerateTypeHierarchy(Type type) { - var interfaces = type.GetInterfaces(); - for (int i = 0; i < interfaces.Length; i++) + var visited = new HashSet(); + var stack = new Stack(); + stack.Push(type); + while (stack.Count > 0) { - yield return interfaces[i]; - } - - while (type is not null) - { - yield return type; - type = type.BaseType; + var current = stack.Pop(); + if (!visited.Add(current)) continue; + foreach (var interfaceType in current.GetInterfaces()) + { + yield return interfaceType; + } + for (var baseType = current; baseType is not null; baseType = baseType.BaseType) + { + yield return baseType; + } + foreach (var property in current.GetProperties()) + { + stack.Push(property.PropertyType); + } } } From 0af759619872bc4cc10e5e9f2d9304cff709188a Mon Sep 17 00:00:00 2001 From: ncguilbeault Date: Fri, 14 Aug 2026 13:37:43 +0100 Subject: [PATCH 2/2] Add tests for nested and transitive nested property types --- .../ExpressionScriptingTests.cs | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/Bonsai.Scripting.Expressions.Tests/ExpressionScriptingTests.cs b/src/Bonsai.Scripting.Expressions.Tests/ExpressionScriptingTests.cs index 2d41330..6a8abfd 100644 --- a/src/Bonsai.Scripting.Expressions.Tests/ExpressionScriptingTests.cs +++ b/src/Bonsai.Scripting.Expressions.Tests/ExpressionScriptingTests.cs @@ -70,6 +70,23 @@ public Task TestCasingCompatibility(string expression, TSource return AssertExpressionTransform(expression, value, expected); } + [TestMethod] + [DataRow("it.Value == NestedEnum.B", true)] + [DataRow("NestedEnum(it.Value + 1)", NestedEnum.C)] + public Task TestNestedPropertyType(string expression, TResult expected) + { + return AssertExpressionTransform(expression, new NestedElement { Value = NestedEnum.B }, expected); + } + + [TestMethod] + [DataRow("it.Element.Value == NestedEnum.B", true)] + [DataRow("NestedElement(object(it.Element)).Value", NestedEnum.B)] + public Task TestTransitiveNestedPropertyType(string expression, TResult expected) + { + var value = new NestedContainer { Element = new NestedElement { Value = NestedEnum.B } }; + return AssertExpressionTransform(expression, value, expected); + } + [TestMethod] [DataRow("")] [DataRow("string(it)")] @@ -79,6 +96,18 @@ public Task TestInvalidExpression(string expression) AssertExpressionTransform(expression, 42, (object)null)); } + public enum NestedEnum { A, B, C } + + public class NestedElement + { + public NestedEnum Value { get; set; } + } + + public class NestedContainer + { + public NestedElement Element { get; set; } + } + class Return(TValue value) : Source { public TValue Value { get; } = value;