Тело выражения должно быть типа «MethodCallExpression»

У меня есть функция -

public async Task DoWork(Frequency value) { // do work }

Идея состоит в том, чтобы добавить эту функцию в Hangfire в качестве повторяющегося задания.

Добавление задания явно работает, например:

RecurringJob.AddOrUpdate("triggerId", () => DoWork(frequency), Cron.Daily())

Однако, если я хочу создать функцию для добавления триггеров

private void AddTrigger(string triggerId, Frequency frequency, Func<Frequency, Task> trigger)
{
    RecurringJob.AddOrUpdate(triggerId, () => trigger(frequency), Cron.Daily());
}

Я получаю сообщение об ошибке Expression body should be of type 'MethodCallExpression'

Когда я отлаживаю, кажется, что это объекты одного типа. Что мне здесь не хватает, что вызывает эту ошибку?

() => trigger(frequency)    {Method = {System.Threading.Tasks.Task <<>m0>b__0()}}   object {System.Func<System.Threading.Tasks.Task>}
() => DoWork(frequency)     {Method = {System.Threading.Tasks.Task <<>m0>b__0()}}   object {System.Func<System.Threading.Tasks.Task>}

🤔 А знаете ли вы, что...
C# позволяет создавать собственные библиотеки классов и использовать их в других проектах.


36
1

Ответ:

Решено

Перегрузка RecurringJob.AddOrUpdate, которую вы вызываете, принимает Expression<Func<Task>>. Это дерево выражений, представляющий вызов, который возвращает задачу.

К сожалению, RecurringJob.AddOrUpdate требует, чтобы это дерево выражений представляло вызов метода — оно вызывает Job.FromExpression, что в итоге приводит к этот код. Каждый Job в конечном итоге строится из MethodInfo. Ваше лямбда-выражение является вызовом через параметр, поэтому оно не работает.

Вы можете обернуть вызов в вызов метода, как показано ниже - я не знаю, будет ли это работать на самом деле... вы можете обнаружить, что у вас есть много заданий с именем «Выполнение».

private void AddTrigger(string triggerId, Frequency frequency, 
                        Func<Frequency, Task> trigger)
{
    var wrapper = new TriggerWrapper(() => trigger(frequency));
    RecurringJob.AddOrUpdate(triggerId, () => wrapper.Execute(), Cron.Daily());
}

private class TriggerWrapper
{
    private Func<Task> func;

    internal TriggerWrapper(Func<Task> func) => this.func = func;

    public Task Execute() => func();
}