diff --git a/src/DynamicExpresso.Core/Parsing/Parser.cs b/src/DynamicExpresso.Core/Parsing/Parser.cs index 85d7dd9..fa3a1c3 100644 --- a/src/DynamicExpresso.Core/Parsing/Parser.cs +++ b/src/DynamicExpresso.Core/Parsing/Parser.cs @@ -2004,6 +2004,37 @@ private static MethodData[] FindBestMethod(IEnumerable methods, Expr return applicable; } + private static Type GetConcreteTypeForGenericMethod(Type type, List promotedArgs, MethodData method) + { + if (type.IsGenericType) + { + //Generic type + var genericArguments = type.GetGenericArguments(); + var concreteTypeParameters = new Type[genericArguments.Length]; + + for (var i = 0; i < genericArguments.Length; i++) + { + concreteTypeParameters[i] = GetConcreteTypeForGenericMethod(genericArguments[i], promotedArgs,method); + } + + return type.GetGenericTypeDefinition().MakeGenericType(concreteTypeParameters); + } + else if (type.ContainsGenericParameters) + { + //T case + //try finding an actual parameter for the generic + for (var i = 0; i < promotedArgs.Count; i++) + { + if (method.Parameters[i].ParameterType == type) + { + return promotedArgs[i].Type; + } + } + } + + return type;//already a concrete type + } + private static bool CheckIfMethodIsApplicableAndPrepareIt(MethodData method, Expression[] args) { if (method.Parameters.Count(y => !y.HasDefaultValue && !HasParamsArrayType(y)) > args.Length) @@ -2112,25 +2143,11 @@ private static bool CheckIfMethodIsApplicableAndPrepareIt(MethodData method, Exp { if (x.HasDefaultValue) { - var parameterType = x.ParameterType; - if (x.ParameterType.ContainsGenericParameters) - { - //try finding an actual parameter for the generic - for(var i = 0; i < promotedArgs.Count; i++) - { - var actualArg = promotedArgs[i]; - if (method.Parameters[i].ParameterType == x.ParameterType) - { - parameterType = actualArg.Type; - break; - } - } - } - + var parameterType = GetConcreteTypeForGenericMethod(x.ParameterType, promotedArgs, method); return Expression.Constant(x.DefaultValue, parameterType); } - + if (HasParamsArrayType(x)) { diff --git a/test/DynamicExpresso.UnitTest/MemberInvocationTest.cs b/test/DynamicExpresso.UnitTest/MemberInvocationTest.cs index 1601d2b..6558c22 100644 --- a/test/DynamicExpresso.UnitTest/MemberInvocationTest.cs +++ b/test/DynamicExpresso.UnitTest/MemberInvocationTest.cs @@ -325,6 +325,11 @@ public void Method_with_generic_param() Assert.AreEqual(x.MethodWithGenericParamAndDefault(y,y), target.Eval("x.MethodWithGenericParamAndDefault(y,y)", parameters)); Assert.AreEqual(x.MethodWithGenericParamAndDefault(y), target.Eval("x.MethodWithGenericParamAndDefault(y)", parameters)); + 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] @@ -567,6 +572,21 @@ public T MethodWithGenericParamAndDefault(T a, T b = default) return a; } + public T MethodWithGenericParamAndDefault1Levels(T a, List b = default) + { + return a; + } + + public T MethodWithGenericParamAndDefault2Levels(T a, List> b = default) + { + return a; + } + + public T MethodWithGenericParamAndDefault2Levels(T a, T2 b, List c = default, List> d = default) + { + return a; + } + public string MethodWithOptionalParam(string param1, string param2 = "2", string param3 = "3") { return string.Format("{0} {1} {2}", param1, param2, param3);