Преобразовать любую заданную функцию в ожидаемую задачу
Целью следующего кода является включение любой заданной функции в ожидаемую функцию. Идея состоит в том, чтобы использовать его при извлечении данных из 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;
}