Patrick Skelton Ответов: 2

Как преобразовать функцию, принимающую функцию func[T], в асинхронную?


У меня есть класс, который имеет функцию, которая запускает предоставленный делегат, который имеет тип Func<T>, как показано в следующем коде.

public static class FunctionRunner
{
	public static int RunSuppliedFunction( Func<int> aFunctionReturningInt ) => aFunctionReturningInt();
}


public int CallingMethod()
{
	return FunctionRunner.RunSuppliedFunction( () => 42 );
}


Это прекрасно компилируется.

Что делать, если я хочу изменить тип делегата на асинхронный, что, как мне кажется, означает, что его тип будет тогда Func<Task<int>> (но я могу ошибаться даже в этом)?

Какой синтаксис мне нужен, чтобы заставить это работать?

Что я уже пробовал:

Кажется, я перепробовал все. Компилятор делает все возможное, чтобы сказать мне, что я делаю неправильно, но у меня сегодня блондинистый день, и я не могу понять этого. (Не ПК, чтобы сказать "светлый день", но поскольку у меня светлые волосы, я думаю, что мне это сойдет с рук.)

Это все, что у меня есть.:

public static class FunctionRunner
{
    public static int RunSuppliedFunction( Func<int> functionReturningInt ) => functionReturningInt();
}

private async Task<int> SomeFunction()
{
    await Task.Delay( 100 );
    return 42;
}

public async Task<int> CallingMethod()
{
    return await FunctionRunner.RunSuppliedFunction( SomeFunction );
}


Что дает сообщение компилятора: "SomeFunction() имеет неправильный тип возвращаемого значения".

2 Ответов

Рейтинг:
5

Patrick Skelton

С помощью полезного толчка от @Richard Deeming я получил код, компилирующийся следующим образом (что также приближает нас на шаг к тому, чтобы показать, в чем смысл всего этого):

public static class FunctionRunner
{
    public static async Task<int> RunSuppliedFunction( bool whichFunction, Func<Task<int>> functionA, Func<Task<int>> functionB ) =>
        ( whichFunction) ? await functionA() : await functionB();
}

public async Task<int> CallingMethod()
{
    bool whichFunction = true;
    return await FunctionRunner.RunSuppliedFunction
    (
        whichFunction,
        async () =>
        {
            await Task.Delay( 100 );
            return 42;
        },
        async () =>
        {
            await Task.Delay( 100 );
            return 43;
        }
    );
}


Рейтинг:
12

Richard Deeming

Возвращаемый тип объекта an async функция должна быть Task<T> или ValueTask<T>, таким образом, ваш тип делегата будет либо Func<Task<T>> или Func<ValueTask<T>>.

Функция runner эффективно не заботится о том, является ли функция асинхронной - она просто вызывает функцию и возвращает результат. Вы можете сделать этот метод универсальным, чтобы разрешить любой тип возвращаемого значения:

public static class FunctionRunner
{
    public static T RunSuppliedFunction<T>(Func<T> theFunction) => theFunction();
}
Если делегат возвращается Task<T> или ValueTask<T>, вызывающий метод должен будет либо вернуть результат непосредственно, либо быть помечен как async и await результат:
private Task<int> theAsyncFunction = ...;

// Either:
public Task<int> CallingMethod() => FunctionRunner.RunSuppliedFunction(theAsyncFunction);

// Or:
public async Task<int> CallingMethod() => await FunctionRunner.RunSuppliedFunction(theAsyncFunction);
ТБХ, я не думаю, что это так. FunctionRunner класс добавляет сюда все, что угодно - вы можете просто позвонить в Func<> непосредственно.
// Either:
public Task<int> CallingMethod() => theAsyncFunction();

// Or:
public async Task<int> CallingMethod() => await theAsyncFunction();

Редактировать: Основываясь на обновленном вопросе, вам все равно нужно обновить определение RunSuppliedFunction:
public static class FunctionRunner
{
    public static Task<int> RunSuppliedFunction( Func<Task<int>> functionReturningInt ) => functionReturningInt();
}

private async Task<int> SomeFunction()
{
    await Task.Delay( 100 );
    return 42;
}

public async Task<int> CallingMethod()
{
    return await FunctionRunner.RunSuppliedFunction( SomeFunction );
}


Patrick Skelton

Спасибо за ответ, Ричард. Я улучшил свой вопрос, чтобы быть немного ближе к тому, что я на самом деле пытаюсь сделать. Я попытался следовать вашему коду, но все равно получил ошибку, упомянутую в вопросе. (Вы правы, что в приведенном мною примере FunctionRunner ничего не добавляет. В реальном коде он получает три делегата и решает, какой из них запустить в зависимости от определенных условий. Я сократил его, чтобы дать как можно более короткий пример кода.)