Я почти понимаю, почему возникает эта конкретная проблема (хотя я более чем приветствую объяснение непрофессионала, если вы найдете время!), Я уверен, что это связано с боксом/распаковкой, которые я не буду пытаться объяснить неправильно.
С моим текущим знанием (или его отсутствием) ситуации я не уверен, как лучше всего действовать, чтобы разрешить ее.
Вот довольно упрощенное консольное приложение, показывающее мою проблему:
static void Main(string[] args)
{
try
{
// succeeds
IEnumerable<Expression<Func<TestCase1Impl, dynamic>>> results1 =
typeof(ITestCase1).GetMethods().Select(m => buildDynamicExpression(new TestCase1Impl(), m));
Console.WriteLine("{0} methods processed on ITestCase1", results1.Count().ToString());
// succeeds
IEnumerable<Expression<Func<TestCase2Impl, int>>> results2 =
typeof(ITestCase2).GetMethods().Select(m => buildTypedExpression(new TestCase2Impl(), m));
Console.WriteLine("{0} methods processed on ITestCase2", results2.Count().ToString());
// fails
IEnumerable<Expression<Func<TestCase2Impl, dynamic>>> results3 =
typeof(ITestCase2).GetMethods().Select(m => buildDynamicExpression(new TestCase2Impl(), m));
Console.WriteLine("{0} methods processed on ITestCase2", results3.Count().ToString());
}
catch (Exception ex)
{
Console.WriteLine("Failed: {0}", ex.ToString());
}
Console.ReadKey();
}
private static Expression<Func<T, dynamic>> buildDynamicExpression<T>(T arg, MethodInfo method)
{
ParameterExpression param = Expression.Parameter(typeof(T));
MethodCallExpression[] args = new MethodCallExpression[0]; // none of the methods shown take arguments
return Expression.Lambda<Func<T, dynamic>>(Expression.Call(param, method, args), new ParameterExpression[] { param });
}
private static Expression<Func<T, int>> buildTypedExpression<T>(T arg, MethodInfo method)
{
ParameterExpression param = Expression.Parameter(typeof(T));
MethodCallExpression[] args = new MethodCallExpression[0]; // none of the methods shown take arguments
return Expression.Lambda<Func<T, int>>(Expression.Call(param, method, args), new ParameterExpression[] { param });
}
public interface ITestCase1
{
string Method1();
List<int> Method2();
Program Method3();
}
public interface ITestCase2
{
int Method4();
}
private class TestCase1Impl : ITestCase1
{
public string Method1()
{
throw new NotImplementedException();
}
public List<int> Method2()
{
throw new NotImplementedException();
}
public Program Method3()
{
throw new NotImplementedException();
}
}
private class TestCase2Impl : ITestCase2
{
public int Method4()
{
throw new NotImplementedException();
}
}
Выше будет вывод
3 methods processed on ITestCase1
1 methods processed on ITestCase2
Failed: System.ArgumentException: Expression of type 'System.Int32' cannot be used for return type 'System.Object' <irrelevant stack trace follows>
Как это часто бывает с этими проблемами, лучше изучить, с чего вы начали, прежде чем попасть в этот ужасный беспорядок.
Я использую Мок. У меня есть общий интерфейс, широко используемый в моем приложении другими интерфейсами. Мне нужно проверить, что мои потребители интерфейса сначала вызывают определенный метод в общем интерфейсе, прежде чем вызывать какие-либо методы в различных интерфейсах (мне это кажется плохим дизайном в ретроспективе, я могу решить это позже, но для чисто академические причины, я хотел бы сначала решить этот вопрос).
Для этого я динамически генерирую выражения для каждого метода в своих интерфейсах с It.IsAny<T>()
аргументами, которые затем могу передать в mock.Setup(generatedExpression).Callback(doSomethingCommonHere)
.
Вполне может быть, что есть более простой способ сделать это вместо моего построения выражения...?
Однако, если нет, мой вопрос: как лучше всего изменить построение моего выражения, чтобы разрешить типы значений?