diff --git a/Directory.Build.props b/Directory.Build.props
index 3be9ff13..9bec28d2 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -5,7 +5,7 @@
AgileObjects Ltd
AgileObjects.ReadableExpressions
Steve Wilkes
- Copyright © AgileObjects Ltd 2023
+ Copyright © AgileObjects Ltd 2024
en
git
https://github.com/AgileObjects/ReadableExpressions
diff --git a/NuGet/AgileObjects.ReadableExpressions.4.1.2.nupkg b/NuGet/AgileObjects.ReadableExpressions.4.1.2.nupkg
new file mode 100644
index 00000000..10cfae7b
Binary files /dev/null and b/NuGet/AgileObjects.ReadableExpressions.4.1.2.nupkg differ
diff --git a/NuGet/AgileObjects.ReadableExpressions.4.1.2.snupkg b/NuGet/AgileObjects.ReadableExpressions.4.1.2.snupkg
new file mode 100644
index 00000000..feb63794
Binary files /dev/null and b/NuGet/AgileObjects.ReadableExpressions.4.1.2.snupkg differ
diff --git a/src/ReadableExpressions.sln b/src/ReadableExpressions.sln
index e867a962..4cdef28f 100644
--- a/src/ReadableExpressions.sln
+++ b/src/ReadableExpressions.sln
@@ -91,6 +91,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReadableExpressions.Visuali
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReadableExpressions.Visualizers.Vs17.6.ObjectSource", "Visualizers\ReadableExpressions.Visualizers.Vs17.6.ObjectSource\ReadableExpressions.Visualizers.Vs17.6.ObjectSource.csproj", "{EFF649F7-ABD2-49E6-BA1A-07BC34F89AA2}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReadableExpressions.UnitTests.Net8", "Tests\ReadableExpressions.UnitTests.Net8\ReadableExpressions.UnitTests.Net8.csproj", "{E40E25FE-C7FA-4455-87A3-15D41784706E}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -354,6 +356,14 @@ Global
{EFF649F7-ABD2-49E6-BA1A-07BC34F89AA2}.Release|Any CPU.Build.0 = Release|Any CPU
{EFF649F7-ABD2-49E6-BA1A-07BC34F89AA2}.Release|x86.ActiveCfg = Release|Any CPU
{EFF649F7-ABD2-49E6-BA1A-07BC34F89AA2}.Release|x86.Build.0 = Release|Any CPU
+ {E40E25FE-C7FA-4455-87A3-15D41784706E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E40E25FE-C7FA-4455-87A3-15D41784706E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E40E25FE-C7FA-4455-87A3-15D41784706E}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {E40E25FE-C7FA-4455-87A3-15D41784706E}.Debug|x86.Build.0 = Debug|Any CPU
+ {E40E25FE-C7FA-4455-87A3-15D41784706E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E40E25FE-C7FA-4455-87A3-15D41784706E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E40E25FE-C7FA-4455-87A3-15D41784706E}.Release|x86.ActiveCfg = Release|Any CPU
+ {E40E25FE-C7FA-4455-87A3-15D41784706E}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -394,6 +404,7 @@ Global
{53A69151-1721-4ED5-BB65-6A750D46B133} = {E2401C71-C5F2-46FB-B5A3-E6EFB85106B9}
{CAC4A53F-D4B9-4AD5-864A-F1141ECE91DA} = {4A12EE3E-81ED-4842-A69F-9D15413DC46D}
{EFF649F7-ABD2-49E6-BA1A-07BC34F89AA2} = {4A12EE3E-81ED-4842-A69F-9D15413DC46D}
+ {E40E25FE-C7FA-4455-87A3-15D41784706E} = {E2401C71-C5F2-46FB-B5A3-E6EFB85106B9}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {7EFE121E-7A84-43A4-8C76-7EE70DF2736A}
diff --git a/src/ReadableExpressions.sln.DotSettings b/src/ReadableExpressions.sln.DotSettings
index 5bd4690c..8321d9ab 100644
--- a/src/ReadableExpressions.sln.DotSettings
+++ b/src/ReadableExpressions.sln.DotSettings
@@ -4,6 +4,10 @@
<Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" />
<Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" />
<Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" />
+ <Policy><Descriptor Staticness="Static" AccessRightKinds="Private" Description="Static readonly fields (private)"><ElementKinds><Kind Name="READONLY_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /></Policy>
+ <Policy><Descriptor Staticness="Any" AccessRightKinds="Private" Description="Constant fields (private)"><ElementKinds><Kind Name="CONSTANT_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /></Policy>
+ <Policy><Descriptor Staticness="Any" AccessRightKinds="Protected, ProtectedInternal, Internal, Public, PrivateProtected" Description="Constant fields (not private)"><ElementKinds><Kind Name="CONSTANT_FIELD" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></Policy>
+ <Policy><Descriptor Staticness="Any" AccessRightKinds="Any" Description="Local constants"><ElementKinds><Kind Name="LOCAL_CONSTANT" /></ElementKinds></Descriptor><Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /></Policy>
<Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
<Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
<Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
@@ -45,4 +49,5 @@
<Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
<Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
<Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
- DO_NOTHING
\ No newline at end of file
+ DO_NOTHING
+ True
\ No newline at end of file
diff --git a/src/ReadableExpressions/Extensions/InternalEnumerableExtensions.cs b/src/ReadableExpressions/Extensions/InternalEnumerableExtensions.cs
index 00eaa0bb..24c20569 100644
--- a/src/ReadableExpressions/Extensions/InternalEnumerableExtensions.cs
+++ b/src/ReadableExpressions/Extensions/InternalEnumerableExtensions.cs
@@ -35,7 +35,7 @@ public static ReadOnlyCollection ToReadOnlyCollection(
this IList items)
{
return items.Count != 0
- ? new ReadOnlyCollection(items)
+ ? new(items)
: Enumerable.EmptyReadOnlyCollection;
}
diff --git a/src/ReadableExpressions/Extensions/InternalExpressionExtensions.cs b/src/ReadableExpressions/Extensions/InternalExpressionExtensions.cs
index da0567f3..e9db841c 100644
--- a/src/ReadableExpressions/Extensions/InternalExpressionExtensions.cs
+++ b/src/ReadableExpressions/Extensions/InternalExpressionExtensions.cs
@@ -9,6 +9,7 @@
#endif
using System.Reflection;
using NetStandardPolyfills;
+using Translations;
#if NET35
using static Microsoft.Scripting.Ast.ExpressionType;
#else
@@ -69,13 +70,10 @@ public static bool IsReturnable(this Expression expression)
public static bool IsReturnable(this BlockExpression block)
=> block.HasReturnType() && block.Result.IsReturnable();
- public static bool IsCapturedValue(
- this Expression expression,
- out object capturedValue,
- out bool isStatic)
+ public static bool IsCapture(this Expression expression, out Capture capture)
{
- capturedValue = null;
- isStatic = false;
+ capture = new();
+
var capturedMemberAccesses = new List();
while (true)
@@ -102,14 +100,15 @@ public static bool IsCapturedValue(
return false;
}
- var declaringType = capturedMemberAccesses.LastOrDefault()?.DeclaringType;
+ var declaringType = capturedMemberAccesses
+ .LastOrDefault()?.DeclaringType;
if (captureConstant.Type != declaringType)
{
return false;
}
- capturedValue = captureConstant.Value;
+ capture.Object = captureConstant.Value;
break;
case Convert:
@@ -117,7 +116,7 @@ public static bool IsCapturedValue(
continue;
case null:
- isStatic = true;
+ capture.IsStatic = true;
break;
default:
@@ -131,9 +130,10 @@ public static bool IsCapturedValue(
for (var i = capturedMemberAccesses.Count - 1; i >= 0; --i)
{
- capturedValue = capturedMemberAccesses[i].GetValue(capturedValue);
+ capture.Object = capturedMemberAccesses[i].GetValue(capture.Object);
}
+ capture.Type = capturedMemberAccesses[0].GetMemberInfoType();
return true;
}
}
diff --git a/src/ReadableExpressions/Extensions/InternalReflectionExtensions.cs b/src/ReadableExpressions/Extensions/InternalReflectionExtensions.cs
index 318e8359..fa866eaa 100644
--- a/src/ReadableExpressions/Extensions/InternalReflectionExtensions.cs
+++ b/src/ReadableExpressions/Extensions/InternalReflectionExtensions.cs
@@ -1,9 +1,8 @@
namespace AgileObjects.ReadableExpressions.Extensions
{
-#if FEATURE_VALUE_TUPLE
using System;
-#endif
using System.Collections.Generic;
+ using System.Linq;
using System.Reflection;
using NetStandardPolyfills;
using Translations.Reflection;
@@ -49,18 +48,105 @@ public static string GetKeywordOrNull(this IType type)
}
public static object GetValue(this MemberInfo member, object subject)
- {
- var hasSubject = subject != null;
+ => member.TryGetValue(subject, out var value) ? value : null;
+ public static Type GetMemberInfoType(this MemberInfo member)
+ {
return member switch
{
- FieldInfo field when hasSubject || field.IsStatic => field.GetValue(subject),
- PropertyInfo property when hasSubject || property.IsStatic() => property.GetValue(subject,
- Enumerable