Кортежи против пользовательской структуры для асинхронной версии метода с параметром ref/out

Рассмотрим API C# с методом, который имеет параметр out или ref, например:

Person FindPerson(string name, out int searchTime);

Не будем обращать внимание на то, что параметры out и ref обычно являются дизайнерским запахом, допустим, это устаревший API и мы не можем изменить сигнатуру его существующих методов. Но нам нужно расширить API для поддержки асинхронного выполнения (Windows Phone, приложения WinRT). Вот реализация, которая не компилируется:

Task<Person> FindPersonAsync(string name, out int searchTime)
{
    return Task.Factory.StartNew(() => this.FindPersonAsync(name, out searchTime));
}

Эта реализация не будет компилироваться из-за параметра out. Поэтому нам нужно изменить подпись API. Один из способов — изменить результат с «задача человека» на «задача кортежа человека и целого числа», т. е. реализация делегата будет возвращать кортеж человека и целого числа. Второй вариант — определить пользовательскую структуру.

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

Преимущество пользовательской структуры: клиентский код, использующий кортежи, должен будет ссылаться на элементы Tuple, используя имена Item1 и Item2. Это неясно.

Я не нашел никаких рекомендаций и пока решил использовать кортежи. Но мне интересно, есть ли рекомендуемая практика для работы с такими методами при расширении API с поддержкой asyns.


person Vagif Abilov    schedule 26.03.2013    source источник
comment
Это очень субъективно. Они оба работают, ни один из них не идеален, время выполнения не имеет значения. Выбрать свой яд. Проверьте этот мета-вопрос   -  person Hans Passant    schedule 27.03.2013
comment
Ваш код может быть более понятным, если вы используете TimeSpan вместо int для результата searchTime.   -  person Sam Harwell    schedule 30.03.2013
comment
Согласитесь, TimeSpan может быть лучшим вариантом для нового API. Но я имею дело с существующей и хотел бы сохранить асинхронную версию как можно ближе к оригиналу.   -  person Vagif Abilov    schedule 31.03.2013


Ответы (1)


Мне не известны какие-либо передовые методы или рекомендации по этому вопросу; но по моему собственному опыту Tuple делает код уродливым и бессмысленным. Что означает Item1, когда вы его видите?

Я всегда использую собственный класс и придерживаюсь некоторых соглашений:

  • Имя пользовательского класса заканчивается на Result, например FindPersonResult.
  • Создайте класс как POCO без специальной логики в конструкторе. Это предотвращает любые неожиданности при работе с другими частями системы и другими API (особенно при сериализации и десериализации).
  • Всегда устанавливайте начальное значение полей/свойств коллекции (массивы, списки и т. д.) пустым, а не нулевым. Это тоже помогает во многих случаях.

Имейте в виду, что это всего лишь мой личный опыт в этом вопросе, который сработал для меня без проблем.

person Kaveh Shahbazian    schedule 09.05.2013
comment
Привет, Каве, я согласен с вами по поводу безобразия имен на основе кортежей, безусловно, это важный фактор при выборе между различными альтернативами. - person Vagif Abilov; 09.05.2013