Создание реализаций интерфейса async
В настоящее время я пытаюсь сделать мое приложение использующим некоторые методы Async.
Весь мой IO выполняется через явные реализации интерфейса, и я немного смущен тем, как сделать операции async.
Как я вижу, у меня есть два варианта реализации:
interface IIO
{
void DoOperation();
}
ОПЦИЯ1:
Сделайте неявное выполнение async и ожидайте результат в неявной реализации.
class IOImplementation : IIO
{
async void DoOperation()
{
await Task.Factory.StartNew(() =>
{
//WRITING A FILE OR SOME SUCH THINGAMAGIG
});
}
#region IIO Members
void IIO.DoOperation()
{
DoOperation();
}
#endregion
}
OPTION2:
Сделайте явную реализацию async и ожидайте задачу из неявной реализации.
class IOAsyncImplementation : IIO
{
private Task DoOperationAsync()
{
return new Task(() =>
{
//DO ALL THE HEAVY LIFTING!!!
});
}
#region IIOAsync Members
async void IIO.DoOperation()
{
await DoOperationAsync();
}
#endregion
}
Является ли одна из этих реализаций лучше, чем другая, или есть другой способ, о котором я не думаю?
Ответы
Ответ 1
Ни один из этих вариантов не является правильным. Вы пытаетесь реализовать синхронный интерфейс асинхронно. Не делай этого. Проблема в том, что при возврате DoOperation()
операция еще не завершена. Хуже того, если во время операции происходит исключение (что очень часто встречается с операциями ввода-вывода), у пользователя не будет возможности справиться с этим исключением.
Что вам нужно сделать, так это изменить интерфейс, чтобы он был асинхронным:
interface IIO
{
Task DoOperationAsync(); // note: no async here
}
class IOImplementation : IIO
{
public async Task DoOperationAsync()
{
// perform the operation here
}
}
Таким образом, пользователь увидит, что операция async
, и они смогут await
его. Это также в значительной степени заставляет пользователей вашего кода переключаться на async
, но это неизбежно.
Кроме того, я предполагаю, что использование StartNew()
в вашей реализации - всего лишь пример, вам не нужно, чтобы реализовать асинхронный ввод-вывод. (И new Task()
еще хуже, это даже не работает, потому что вы не Start()
Task
.)
Ответ 2
Лучшее решение - ввести другой интерфейс для асинхронных операций. Новый интерфейс должен наследовать от исходного интерфейса.
Пример:
interface IIO
{
void DoOperation();
}
interface IIOAsync : IIO
{
Task DoOperationAsync();
}
class ClsAsync : IIOAsync
{
public void DoOperation()
{
DoOperationAsync().GetAwaiter().GetResult();
}
public async Task DoOperationAsync()
{
//just an async code demo
await Task.Delay(1000);
}
}
class Program
{
static void Main(string[] args)
{
IIOAsync asAsync = new ClsAsync();
IIO asSync = asAsync;
Console.WriteLine(DateTime.Now.Second);
asAsync.DoOperation();
Console.WriteLine("After call to sync func using Async iface: {0}",
DateTime.Now.Second);
asAsync.DoOperationAsync().GetAwaiter().GetResult();
Console.WriteLine("After call to async func using Async iface: {0}",
DateTime.Now.Second);
asSync.DoOperation();
Console.WriteLine("After call to sync func using Sync iface: {0}",
DateTime.Now.Second);
Console.ReadKey(true);
}
}
P.S.
Перепроектируйте свои асинхронные операции, чтобы они возвращали Task вместо void, если вы действительно не должны возвращать void.