diff --git a/src/DynamicExpresso.Core/Parsing/Parser.cs b/src/DynamicExpresso.Core/Parsing/Parser.cs index 9752f883..4cf72cae 100644 --- a/src/DynamicExpresso.Core/Parsing/Parser.cs +++ b/src/DynamicExpresso.Core/Parsing/Parser.cs @@ -1943,7 +1943,15 @@ private static bool CheckIfMethodIsApplicableAndPrepareIt(MethodData method, Exp if (paramsArrayTypeFound != null) { - var promoted = PromoteExpression(currentArgument, paramsArrayTypeFound.GetElementType(), true); + var paramsArrayElementType = paramsArrayTypeFound.GetElementType(); + if (paramsArrayElementType.IsGenericParameter) + { + paramsArrayPromotedArgument = paramsArrayPromotedArgument ?? new List(); + paramsArrayPromotedArgument.Add(currentArgument); + continue; + } + + var promoted = PromoteExpression(currentArgument, paramsArrayElementType, true); if (promoted != null) { paramsArrayPromotedArgument = paramsArrayPromotedArgument ?? new List(); @@ -1960,7 +1968,17 @@ private static bool CheckIfMethodIsApplicableAndPrepareIt(MethodData method, Exp method.HasParamsArray = true; var paramsArrayElementType = paramsArrayTypeFound.GetElementType(); if (paramsArrayElementType == null) - throw new Exception("Type is not an array, element not found"); + throw CreateParseException(-1, ErrorMessages.ParamsArrayTypeNotAnArray); + + if (paramsArrayElementType.IsGenericParameter) + { + var actualTypes = paramsArrayPromotedArgument.Select(_ => _.Type).Distinct().ToArray(); + if (actualTypes.Length != 1) + throw CreateParseException(-1, ErrorMessages.MethodTypeParametersCantBeInferred, method.MethodBase); + + paramsArrayElementType = actualTypes[0]; + } + promotedArgs.Add(Expression.NewArrayInit(paramsArrayElementType, paramsArrayPromotedArgument)); } @@ -2030,6 +2048,16 @@ private static Dictionary ExtractActualGenericArguments( if (!actualType.IsGenericParameter) extractedGenericTypes[requestedType.Name] = actualType; } + else if (requestedType.IsArray && actualType.IsArray) + { + var innerGenericTypes = ExtractActualGenericArguments( + new[] { requestedType.GetElementType() }, + new[] { actualType.GetElementType() + }); + + foreach (var innerGenericType in innerGenericTypes) + extractedGenericTypes[innerGenericType.Key] = innerGenericType.Value; + } else if (requestedType.ContainsGenericParameters) { if (actualType.IsGenericParameter) diff --git a/src/DynamicExpresso.Core/Resources/ErrorMessages.Designer.cs b/src/DynamicExpresso.Core/Resources/ErrorMessages.Designer.cs index 37e4f973..5f738175 100644 --- a/src/DynamicExpresso.Core/Resources/ErrorMessages.Designer.cs +++ b/src/DynamicExpresso.Core/Resources/ErrorMessages.Designer.cs @@ -337,11 +337,33 @@ internal static string InvalidMethodCall { return ResourceManager.GetString("InvalidMethodCall", resourceCulture); } } - - /// - /// Looks up a localized string similar to Invalid real literal '{0}'. - /// - internal static string InvalidRealLiteral { + + /// + /// Looks up a localized string similar to Params array type is not an array, element not found + /// + internal static string ParamsArrayTypeNotAnArray + { + get + { + return ResourceManager.GetString("ParamsArrayTypeNotAnArray", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The type arguments for method '{0}' cannot be inferred from the usage. + /// + internal static string MethodTypeParametersCantBeInferred + { + get + { + return ResourceManager.GetString("MethodTypeParametersCantBeInferred", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid real literal '{0}'. + /// + internal static string InvalidRealLiteral { get { return ResourceManager.GetString("InvalidRealLiteral", resourceCulture); } diff --git a/src/DynamicExpresso.Core/Resources/ErrorMessages.resx b/src/DynamicExpresso.Core/Resources/ErrorMessages.resx index 440f6d3d..8246a303 100644 --- a/src/DynamicExpresso.Core/Resources/ErrorMessages.resx +++ b/src/DynamicExpresso.Core/Resources/ErrorMessages.resx @@ -255,4 +255,10 @@ '>' expected + + The type arguments for method '{0}' cannot be inferred from the usage. + + + Params array type is not an array, element not found + \ No newline at end of file diff --git a/test/DynamicExpresso.UnitTest/MemberInvocationTest.cs b/test/DynamicExpresso.UnitTest/MemberInvocationTest.cs index 56a3cdb9..4958c70f 100644 --- a/test/DynamicExpresso.UnitTest/MemberInvocationTest.cs +++ b/test/DynamicExpresso.UnitTest/MemberInvocationTest.cs @@ -1,6 +1,7 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; +using DynamicExpresso.Exceptions; using NUnit.Framework; namespace DynamicExpresso.UnitTest @@ -370,7 +371,21 @@ public void Overload_paramsArray_methods_with_compatible_type_params() target.SetVariable("x", x); Assert.AreEqual(3, target.Eval("x.OverloadMethodWithParamsArray(2, 3, 1)")); } - + + + [Test] + public void Generic_method_with_params() + { + var target = new Interpreter(); + target.Reference(typeof(Utils)); + + var listInt = target.Eval>("Utils.Array(1, 2, 3)"); + Assert.AreEqual(new[] { 1, 2, 3 }, listInt); + + // type parameter can't be inferred from usage + Assert.Throws(() => target.Eval>("Utils.Array(1,\"str\", 3)")); + } + [Test] public void Method_with_optional_param() { @@ -555,5 +570,13 @@ public string AMethod() return "Ciao mondo"; } } + + private static class Utils + { + public static List Array(params T[] array) + { + return new List(array); + } + } } }