Интерфейсы и асинхронные методы

У меня есть приложение. Это приложение использует интерфейс для доступа к базе данных. Этот интерфейс может быть реализован многими классами. Например, один использует EF 4.4, но другие классы могут использовать EF5, который является более эффективным. В будущем, возможно, я буду использовать EF6, потому что он использует методы async. В этом примере все методы используют EF, но, возможно, другие параметры могут использоваться другими способами.

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

В настоящий момент все методы классов не async, но в будущем, если я использую EF6, я бы хотел использовать методы async, поэтому я не знаю, возможно ли, что класс, который использует EF6 и реализует интерфейс, может использовать методы async.

Для асинхронных методов EF6 я бы использовал шаблон async/awiat, поэтому в методе моего класса мне нужно использовать атрибут async. Это позволяет мне использовать ключевое слово await, когда я вызываю метод async для EF6.

Но этот класс может реализовать интерфейс, который в первый раз предназначен для синхронных методов?

Есть ли способ, которым в основном приложении я могу использовать многие реализации без необходимости изменять код? Некоторые реализации будут использовать асинхронные методы, в то время как другие будут синхронными.

Ответ 1

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

Реальная разница в том, что ваши методы async должны будут возвращать Task или Task<T>, тогда как неасинхронные методы, скорее всего, в настоящее время возвращают void или некоторый тип, T напрямую.

Если вы хотите, чтобы "будущее доказательство" вашего приложения было одним из вариантов, убедитесь, что все ваши интерфейсы возвращают Task или Task<T>, а для ваших реализаций EF4/EF5 вы завершаете результаты в завершенной задаче, даже если они Выполняется синхронно.

Task.FromResult был добавлен в .NET 4.5, но если у вас его нет, вы можете написать свой собственный достаточно легко:

public static Task<T> FromResult<T>(T result)
{
    var tcs = new TaskCompletionSource<T>();
    tcs.SetResult(result);
    return tcs.Task;
}

Вы также можете написать метод CompletedTask, который просто возвращает задание, которое уже выполнено: (Он кэширует одну задачу по соображениям эффективности.)

private static Task _completedTask;
public static Task CompletedTask()
{
    return _completedTask ?? initCompletedTask();
}

private static Task initCompletedTask()
{
    var tcs = new TaskCompletionSource<object>();
    tcs.SetResult(null);
    _completedTask = tcs.Task;
    return _completedTask;
}

Эти два метода упростят процесс, когда все ваши методы возвращают некоторый тип Task, хотя это сделает ваш код немного более беспорядочным, пока вы не сможете использовать С# 5.0, чтобы иметь возможность await результат.