Преобразовать любую заданную функцию в ожидаемую задачу

Целью следующего кода является включение любой заданной функции в ожидаемую функцию. Идея состоит в том, чтобы использовать его при извлечении данных из db, предоставляя коду гибкость либо использовать функции синхронной выборки (наложение моего текущего ORM), либо использовать те же функции, что и async.

Я знаю, что может быть много чего не так с концепцией кода. К настоящему моменту я просто пытался избавиться от ошибок компилятора, поэтому я могу запустить код и проверить его поведение. Но, конечно, я открыт для обсуждения концепции заранее, и если вся идея позади не так, используйте мое время более эффективно, чтобы найти другое решение.

async static void Main()
{
    // The following line gives a compiler error:
    // Error    1   The best overloaded method match for 'CastFuncToTask<int>(System.Func<int>)' has some invalid arguments 
    int task = await CastFuncToTask<int>(TestFunc(2));
}

private static Task<T> CastFuncToTask<T>(Func<T> func)
{
    TaskCompletionSource<T> taskCompletionSource = new TaskCompletionSource<T>();
    T result = func.Invoke();
    taskCompletionSource.SetResult(result);
    return taskCompletionSource.Task;
}

private static int TestFunc(int testInt) 
{
    return testInt * 2;
}

Ответ 1

Запустив .NET 4.5, вы можете значительно упростить свой код, выполнив:

int task = await Task.FromResult(TestFunc(2));

Не нужно оборачивать его в TaskCompletionSource.

Я знаю, что может быть много вещей не так с концепцией кода.

Если вы пытаетесь выполнить асинхронный запрос к базе данных, это решение определенно не поможет. Это только искусственно оборачивает ваш результат в Task. Если вы действительно хотите запрашивать вашу базу данных асинхронно, вам нужно использовать асинхронные методы, предоставляемые вашим поставщиком базы данных.

Если вы используете MySQL и ищете драйвер, который поддерживает асинхронный режим, посмотрите на Dapper

Ответ 2

измените его на

int task = await CastFuncToTask<int>(()=>TestFunc(2));

В вашем коде ввод, предоставленный для CastFuncToTask, является int (что возвращает TestFunc.), но ему нужен делегат Func<T>.

Ответ 3

мой метод таков:

public Task<int> SetOffAsync()
{
    return Task<int>.Factory.StartNew(() =>
    { 
        /*do something else*/
        return 42;
    });
}

и вы можете вызвать это:

int var = await SetOffAsync();

Ответ 4

В приложении Windows Forms я подтвердил, что первый вызов блокирует второй. Поэтому лучшим решением было бы использовать Task.Run() с выражением лямбда.

    private async void button1_Click(object sender, EventArgs e)
    {
        button1.Text = "...";
        var result = await Task.FromResult(TestFunc(2));
        button1.Text = result.ToString();
    }

    private async void button2_Click(object sender, EventArgs e)
    {
        button2.Text = "...";
        var result = await Task.Run(() => TestFunc(2));
        button2.Text = result.ToString();
    }

    private int TestFunc(int x)
    {
        System.Threading.Thread.Sleep(5000);
        return x;
    }

Компилятор не может знать, что вы не хотите оценивать TestFunc (2), но используете его как делегат и сначала выполняете метод, а Task.FromResult просто завершает return value в Задаче. Это не то, что вы хотите.

Ответ 5

await Task.Run(() => obj.functionname());

Ответ 6

Ниже код может помочь другим:

Примечание: GenericMethod - это имя параметра, которое мы передаем как Func с Input (T1) и output (T2) общего типа. Task Factory предоставит необходимый доступ для запуска вашей задачи.

    public async Task<T2> GenericAsyncCall<T1, T2>(Func<T1, T2> GenericMethod, T1 input)
    {
        var _output = await Task.Factory.StartNew(() => {
            var output = GenericMethod.Invoke(input);
            return output;
        });

        return (T2)_output;
    }