У меня есть класс в приложении .netcore, который используется для постановки в очередь фоновых задач:
public interface IBackgroundTasksService {
void RunBackgroundTask<T>(Expression<Action<T>> methodCall);
}
public class BackgroundTasksService : IBackgroundTasksService {
public void RunBackgroundTask<T>(Expression<Action<T>> methodCall){
// calls to the Backgorund service worker thrid party library with `methodCall` as a param.
// this works as expected
}
}
При вызове других служб это обычный шаблон:
_backgroundTasksService.RunBackgroundTask<MyService>(x => x.Execute(id, name, color));
В этом проблема: при запуске модульных тестов мне нужно, чтобы methodCall
вызывался, а не регистрировался для фонового работника, поэтому я создал заглушку для BackgroundTasksService
:
public class BackgroundTasksServiceStub : IBackgroundTasksService {
public void RunBackgroundTask<T>(Expression<Action<T>> methodCall){
Expression.Lambda(methodCall).Compile().DynamicInvoke(); // this is just one of the attempts (it does not work)
}
}
Я пробовал несколько разных подходов, но пока не нашел ни одного, который бы призывал MyService.Execute
...
Каким будет подход к выполнению метода аргумента?
Как получить экземпляр службы?
Это была всего лишь глупая попытка (иначе метод был бы пуст в вопросе). Я недостаточно знаком с этими выражениями, чтобы сделать их кажущимися.
Я предполагаю, что экземпляр MyService
происходит от внедрения зависимостей (поскольку это единственное место, где создается сервис). Но поскольку это сторонняя библиотека (зависание), я думаю, справедливо предположить, что она исходит от DI.
Благодаря комментариям к вопросу я заставил его работать!
Вот как работает рабочий класс-заглушка:
public class BackgroundTasksServiceStub : IBackgroundTasksService {
private readonly IServiceProvider _serviceProvider;
public BackgroundTasksServiceStub(IServiceProvider serviceProvider){
_serviceProvider = serviceProvider;
}
public void RunBackgroundTask<T>(Expression<Action<T>> methodCall){
var service = _serviceProvider.GetService<T>();
var method = methodCall.Compile();
method(service);
}
}
почему
DynamicInvoke
, когда вы знаете тип действия во время компиляции?Compile
возвращаетAction<T>
, поэтому вы можете либо вызватьInvoke
, либо, что еще короче, напрямую использоватьCompile()(myInstanceOfT)
, каким бы ни был этот экземпляр.