Это хороший стиль С#?

Рассмотрим следующую сигнатуру метода:

public static bool TryGetPolls(out List<Poll> polls, out string errorMessage)

Этот метод выполняет следующие действия:

  • обращается к базе данных для создания списка объектов опроса.
  • возвращает true, если он был успешным, и errorMessage будет пустой строкой
  • возвращает false, если он не был успешным, а errorMessage будет содержать сообщение об исключении.

Это хороший стиль?

Обновление: Допустим, я использую следующую сигнатуру метода:

public static List<Poll> GetPolls()

и в этом методе он не улавливает никаких исключений (поэтому я зависим от вызывающего пользователя для исключения исключений). Как я удаляю и закрываю все объекты, находящиеся в области этого метода? Как только генерируется исключение, код, который закрывает и удаляет объекты в методе, больше не доступен.

Ответ 1

Этот метод пытается сделать три разных вещи:

  • Получить и вернуть список опросов
  • Возвращает логическое значение, указывающее успех
  • Вернуть сообщение об ошибке

Это довольно грязно с точки зрения дизайна.

Лучше всего было бы объявить просто:

public static List<Poll> GetPolls()

Затем пусть этот метод выкинет Exception, если что-то пойдет не так.

Ответ 2

Я верю

public static bool TryGetPolls(out List<Poll> polls)

было бы более уместным. Если метод является TryGet, тогда мое первоначальное предположение было бы основанием ожидать, что он потерпит неудачу, и на вызывающем абоненте будет указано, что делать дальше. Если они не обрабатывают ошибку или хотят получить информацию об ошибке, я ожидаю, что они вызовут соответствующий метод Get.

Ответ 3

Это, безусловно, не идиоматический способ написания С#, что также означает, что он, вероятно, тоже не хороший стиль.

Если у вас есть метод TryGetPolls, значит, вам нужны результаты, если операция завершается успешно, а если нет, то вам все равно, почему это не удается.

Если у вас есть просто метод GetPolls, значит, вы всегда хотите получить результаты, и если это не удается, вы хотите знать, почему в форме Exception.

Смешивание двух происходит где-то посередине, что будет необычным для большинства людей. Поэтому я бы сказал, либо не вернул сообщение об ошибке, либо выбросил Exception при сбое, но не использовал этот нечетный гибридный подход.

Таким образом, ваши сигнатуры методов должны быть либо:

IList<Poll> GetPolls();

или

bool TryGetPolls(out IList<Poll> polls);

(Обратите внимание, что я возвращаю IList<Poll>, а не List<Poll> в любом случае, так как это также хорошая практика для программирования абстракции, а не для реализации.)

Ответ 4

Как правило, я бы сказал нет.

Причина, по которой я говорю "нет", на самом деле не потому, что вы выполняете TryGetX и возвращаете bool с параметром out. Я думаю, что это плохой стиль, потому что вы также возвращаете строку с ошибкой.

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

Вместо этого вы ищете пару методов:

public static bool TryGetPolls( out List<Poll> polls );
public static List<Poll> GetPolls();

Таким образом, пользователь может сделать то, что подходит, и GetPolls может быть реализовано с точки зрения TryGetPolls. Я предполагаю, что ваш static имеет смысл в контексте.

Ответ 5

Рассмотрим возвращение:

  • пустая коллекция
  • NULL

Множественные параметры, для меня, это запах кода. Метод должен делать только ОДИН ВИД.

Рассмотрите возможность создания сообщений об ошибках и их обработки с помощью:

throw new Exception("Something bad happened");
//OR
throw new SomethingBadHappenedException();

Ответ 6

Нет, с моей точки зрения, это очень плохой стиль. Я бы написал это следующим образом:

public static List<Poll> GetPolls();

Если вызов завершился неудачно, отбросьте исключение и поместите сообщение об ошибке в исключение. Для чего нужны исключения, и ваш код станет намного чище, читабельнее и проще в обслуживании.

Ответ 7

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

Однако, возможно, вы просто хотите вернуть "мета" информацию о попытке, и в этом случае вам просто нужен способ вернуть более одного фрагмента информации из одного вызова метода. В этом случае я предлагаю создать класс PollResponse, который содержит два свойства: List < Опроs > Опросы и строка ErrorMessage. Затем верните объект PollResponse в свой метод:

class PollResponse
{
    public List<Poll> Polls { get; }
    public string MetaInformation { get; }
}

Ответ 8

Не совсем - я вижу ряд проблем с этим.

Прежде всего, метод звучит так, как будто вы обычно ожидаете его успеха; ошибки (невозможно подключиться к базе данных, не удается получить доступ к таблице polls и т.д.). В этом случае гораздо разумнее использовать исключения для сообщения об ошибках. Шаблон Try... предназначен для случаев, когда вы часто ожидаете, что вызов "сбой" - например. при анализе строки на целое число имеет хорошие шансы, что строка является пользовательским вводом, который может быть недействительным, поэтому вам нужно иметь быстрый способ справиться с этим - следовательно, TryParse. Здесь не так.

Во-вторых, вы сообщаете об ошибках как значение bool, указывающее наличие или отсутствие ошибки, и строковое сообщение. Как бы вызывающий мог различать различные ошибки? Он, конечно, не может совпадать с текстом сообщения об ошибке - это деталь реализации, которая может быть изменена и может быть локализована. И может быть мир различий между чем-то вроде "Невозможно подключиться к базе данных" (возможно, просто откройте диалоговое окно настроек подключения базы данных в этом случае и разрешите пользователю его редактировать?) И "Подключен к базе данных, но он говорит" Доступ запрещен ",". Ваш API не дает отличного способа отличить их.

Подводя итог: используйте исключения, а не bool + out string для сообщения сообщений. Как только вы это сделаете, вы можете просто использовать List<Poll> как возвращаемое значение, без необходимости использовать аргумент out. И, конечно, переименуйте метод в GetPolls, так как Try... зарезервирован для шаблона bool+out.

Ответ 9

В рекомендациях рекомендуется избегать параметров ref и out, если они не являются абсолютно необходимыми, поскольку они затрудняют использование API (не более цепочки методов, разработчик должен объявить все переменные перед вызовом метода)

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

Лучший способ объявить метод выглядит следующим образом.

public static List<Poll> GetPolls() ... 

а для сообщений об ошибках используется обработка исключений

try 
{
   var pols = GetPols();
   ...
} catch (DbException ex) {
   ... // handle exception providing info to the user or logging it.
}

Ответ 10

Зависит от того, является ли ошибка обычным явлением или действительно ли она является исключением.

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

Если ошибка - это что-то, что является реальной частью обычных операций, как ошибка, охватывающая строку целым числом в методе int.TryParse, метод, который вы создали, будет более уместным.

Я предполагаю, что первое, вероятно, лучший случай для вас.

Ответ 11

Это зависит от того, как часто метод будет терпеть неудачу. В общем случае ошибки в .Net должны сообщаться с помощью Exception. Случай, когда это правило не выполняется, - это когда условие ошибки является частым, а влияние throw ing и исключения на производительность слишком велико.

Для работы с типом базы данных я думаю, что Exception лучше.

Ответ 12

Я бы повторил это так.

public static List<Poll> GetPolls()
{
    ...
}

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

Если вы запустите FxCop, вы захотите изменить List to IList, чтобы он был счастлив.

Ответ 13

Думаю, все в порядке. Я бы предпочел:

enum FailureReasons {}
public static IEnumerable<Poll> TryGetPolls(out FailureReasons reason)

Итак, строки ошибок не живут в коде доступа к данным...

Ответ 14

Методы С# должны действительно делать только одно. Вы пытаетесь сделать три вещи с помощью этого метода. Я бы сделал, как предложили другие, и выдал исключение, если есть ошибка. Другой вариант - создать методы расширения для вашего объекта List.

например. в общедоступном статическом классе:

public static List<Poll> Fill( this List<Poll> polls) {
   // code to retrieve polls
}

Затем, чтобы вызвать это, вы сделали бы что-то вроде:

List<Poll> polls = new List<Poll>().Fill();
if(polls != null)
{
  // no errors occur
}

edit: я только что сделал это. вы можете или не нуждаться в новом операторе в List<Poll>().Fill()

Ответ 15

Укажите свои предположения, ограничения, желания/цели и аргументы; мы должны угадать и/или читать ваш ум, чтобы знать, каковы ваши намерения.

предполагая, что вы хотите, чтобы ваша функция была

  • создать объект списка опросов
  • пресекать все исключения
  • указывает на успешность с помощью boolean
  • и предоставить сообщение об ошибке при ошибке

то указанная выше подпись является прекрасной (хотя проглатывание всех возможных исключений не является хорошей практикой).

Как общий стиль кодирования, он имеет некоторые потенциальные проблемы, о чем говорили другие.

Ответ 16

Существует также этот шаблон, как видно из многих функций Win32.

public static bool GetPolls(out List<Poll> polls)


if(!PollStuff.GetPolls(out myPolls))
  string errorMessage = PollStuff.GetLastError();

Но ИМО это ужасно. Я бы пошел на какое-то исключение, если этот метод не должен запускать 65 раз в секунду в физическом движке 3d-игры или когда-либо.

Ответ 17

Я что-то пропустил? Кажется, что искатель вопроса хочет знать, как очистить ресурсы, если метод не работает.

public static IList<Poll> GetPolls()
{
    try
    {
    }
    finally
    {
        // check that the connection happened before exception was thrown
        // dispose if necessary
        // the exception will still be presented to the caller
        // and the program has been set back into a stable state
    }
}

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