diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4d60c7fc..d0474372 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,10 +17,10 @@ jobs: uses: actions/setup-dotnet@v1 with: dotnet-version: '3.1.x' - - name: Setup .NET Core 5.0 + - name: Setup .NET 7.0 uses: actions/setup-dotnet@v1 with: - dotnet-version: '5.0.x' + dotnet-version: '7.0.x' - name: Setup gitversion run: dotnet tool install --global GitVersion.Tool - name: Calculate version @@ -34,16 +34,16 @@ jobs: run: dotnet build DynamicExpresso.sln --no-restore -c Release /p:Version=${{steps.calc_version.outputs.PROJECT_VERSION}} - name: Test .net core 3.1 run: dotnet test DynamicExpresso.sln --no-build --no-restore -c Release --verbosity normal -f netcoreapp3.1 - - name: Test .net core 5.0 - run: dotnet test DynamicExpresso.sln --no-build --no-restore -c Release --verbosity normal -f netcoreapp5.0 + - name: Test .net core 7.0 + run: dotnet test DynamicExpresso.sln --no-build --no-restore -c Release --verbosity normal -f net7.0 test-win: runs-on: windows-2019 steps: - uses: actions/checkout@v2 - - name: Setup .NET Core 5.0 + - name: Setup .NET 7.0 uses: actions/setup-dotnet@v1 with: - dotnet-version: '5.0.x' + dotnet-version: '7.0.x' - name: Restore packages run: dotnet restore DynamicExpresso.sln - name: Build diff --git a/src/DynamicExpresso.Core/Parsing/Parser.cs b/src/DynamicExpresso.Core/Parsing/Parser.cs index 39ae6b74..320afe9f 100644 --- a/src/DynamicExpresso.Core/Parsing/Parser.cs +++ b/src/DynamicExpresso.Core/Parsing/Parser.cs @@ -2,13 +2,13 @@ using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; -using System.ComponentModel; using System.Dynamic; using System.Globalization; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Runtime.CompilerServices; +using System.Security; using System.Text; using DynamicExpresso.Exceptions; using DynamicExpresso.Resources; @@ -2361,7 +2361,18 @@ private static MethodInfo MakeGenericMethod(MethodData method) .Select(p => actualGenericArgs.TryGetValue(p.Name, out var typ) ? typ : typeof(object)) .ToArray(); - return methodInfo.MakeGenericMethod(genericArgs); + MethodInfo genericMethod = null; + try + { + genericMethod = methodInfo.MakeGenericMethod(genericArgs); + } + catch (ArgumentException e) when (e.InnerException is VerificationException) + { + // this exception is thrown when a generic argument violates the generic constraints + return null; + } + + return genericMethod; } private static Dictionary ExtractActualGenericArguments( @@ -2398,8 +2409,12 @@ private static Dictionary ExtractActualGenericArguments( } else { - var innerGenericTypes = ExtractActualGenericArguments(requestedType.GetGenericArguments(), actualType.GetGenericArguments()); + var requestedInnerGenericArgs = requestedType.GetGenericArguments(); + var actualInnerGenericArgs = actualType.GetGenericArguments(); + if (requestedInnerGenericArgs.Length != actualInnerGenericArgs.Length) + continue; + var innerGenericTypes = ExtractActualGenericArguments(requestedInnerGenericArgs, actualInnerGenericArgs); foreach (var innerGenericType in innerGenericTypes) extractedGenericTypes[innerGenericType.Key] = innerGenericType.Value; } diff --git a/test/DynamicExpresso.UnitTest/DynamicExpresso.UnitTest.csproj b/test/DynamicExpresso.UnitTest/DynamicExpresso.UnitTest.csproj index 801fe939..0a0e7ad1 100644 --- a/test/DynamicExpresso.UnitTest/DynamicExpresso.UnitTest.csproj +++ b/test/DynamicExpresso.UnitTest/DynamicExpresso.UnitTest.csproj @@ -1,7 +1,7 @@ - net5.0;netcoreapp3.1;net462 + net7.0;net5.0;netcoreapp3.1;net462 false diff --git a/test/DynamicExpresso.UnitTest/MemberInvocationTest.cs b/test/DynamicExpresso.UnitTest/MemberInvocationTest.cs index 6558c226..e42727a5 100644 --- a/test/DynamicExpresso.UnitTest/MemberInvocationTest.cs +++ b/test/DynamicExpresso.UnitTest/MemberInvocationTest.cs @@ -328,8 +328,18 @@ public void Method_with_generic_param() Assert.AreEqual(x.MethodWithGenericParamAndDefault1Levels(y), target.Eval("x.MethodWithGenericParamAndDefault1Levels(y)", parameters)); Assert.AreEqual(x.MethodWithGenericParamAndDefault2Levels(y), target.Eval("x.MethodWithGenericParamAndDefault2Levels(y)", parameters)); Assert.AreEqual(x.MethodWithGenericParamAndDefault2Levels(y, w), target.Eval("x.MethodWithGenericParamAndDefault2Levels(y, w)", parameters)); + } + + [Test] + public void Method_with_generic_constraints() + { + var target = new Interpreter(); + var x = new MyTestService(); + target.SetVariable("x", x); + Assert.AreEqual("works", target.Eval("x.GenericMethodWithConstraint(\"works\")")); + Assert.Throws(() => target.Eval("x.GenericMethodWithConstraint(5)"), "This shouldn't throw a System.ArgumentException \"Violates the constraint of type 'T'\""); } [Test] @@ -646,6 +656,11 @@ public long OverloadMethodWithParamsArray(params long[] paramsArray) { return paramsArray.Max(); } + + public T GenericMethodWithConstraint(T input) where T : class + { + return input; + } } private class MyTestServiceCaseInsensitive