Let's say I have a class as follows:
public class AcceptMethods
{
public int Accept(string s, int k = 1)
{
return 1;
}
public int Accept(object s)
{
return 2;
}
public int Accept(IEnumerable<object> s)
{
return 7;
}
public int Accept(IList<object> s)
{
return 4;
}
}
Now, if I try to consume this in code, I use something like this:
object[] list = new object[] { "a", new object[0], "c", "d" };
Assert.AreEqual(7, list.Select((a)=>((int)new AcceptMethods().Accept((dynamic)a))).Sum());
The reason that it's 7, is because overload resolution prefers [IList<object>
] over [IEnumerable<object>
] and [object
], and because [string
, int=default
] has preference over [object
].
In my scenario, I'd like to get the best matching overload using reflection. In other words: 'best' is defined as 'c# overload resolution'. E.g.:
int sum = 0;
foreach (var item in list)
{
var method = GetBestMatching(typeof(AcceptMethods).GetMethods(), item.GetType());
sum += (int)method.Invoke(myObject, new object[]{item});
}
Assert.AreEqual(7, sum);
While the scenario I sketch has only 1 parameter, the solution I seek can have multiple parameters.
Update 1:
Because I received a comment that this is too difficult for SO due to the difficulties of overload resolution implementation (which I am well aware of), I feel inclined to send an update. To give my argument some power, this was my first attempt, which uses the default .NET binder that handles the overload resolution:
private MethodBase GetBestMatching(IEnumerable<MethodInfo> methods, Type[] parameters)
{
return Type.DefaultBinder.SelectMethod(BindingFlags.Instance | BindingFlags.Public | BindingFlags.OptionalParamBinding | BindingFlags.InvokeMethod,
methods.ToArray(), parameters, null);
}
This version already seems to do simple overload resolution correctly, but fails to work with optional parameters. Because .NET afaik works with type binding like I show here, I suppose that the solution could be implemented fairly easy.