Skip to content

Commit

Permalink
generalize default expressions for generic methods
Browse files Browse the repository at this point in the history
  • Loading branch information
israellot committed Jun 10, 2022
1 parent d9f27a3 commit 02362c7
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 16 deletions.
49 changes: 33 additions & 16 deletions src/DynamicExpresso.Core/Parsing/Parser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2004,6 +2004,37 @@ private static MethodData[] FindBestMethod(IEnumerable<MethodData> methods, Expr
return applicable;
}

private static Type GetConcreteTypeForGenericMethod(Type type, List<Expression> promotedArgs, MethodData method)
{
if (type.IsGenericType)
{
//Generic<T> 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)
Expand Down Expand Up @@ -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))
{
Expand Down
20 changes: 20 additions & 0 deletions test/DynamicExpresso.UnitTest/MemberInvocationTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -567,6 +572,21 @@ public T MethodWithGenericParamAndDefault<T>(T a, T b = default)
return a;
}

public T MethodWithGenericParamAndDefault1Levels<T>(T a, List<T> b = default)
{
return a;
}

public T MethodWithGenericParamAndDefault2Levels<T>(T a, List<List<T>> b = default)
{
return a;
}

public T MethodWithGenericParamAndDefault2Levels<T, T2>(T a, T2 b, List<T> c = default, List<List<T2>> d = default)
{
return a;
}

public string MethodWithOptionalParam(string param1, string param2 = "2", string param3 = "3")
{
return string.Format("{0} {1} {2}", param1, param2, param3);
Expand Down

0 comments on commit 02362c7

Please sign in to comment.