2009-08-13 2 views
10

Рассмотрим метод следующую подпись:Это хороший стиль C#?

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

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

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

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

Update: Допустим, я действительно использую метод следующую подпись:

public static List<Poll> GetPolls() 

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

+1

Чтобы форматировать код, добавьте перед ним четыре пробела. Самый простой способ - напечатать/скопировать код, выделить все его и нажать кнопку «код» в редакторе. –

ответ

43

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

  1. Загружать и возвращающие список опросов
  2. возвращают логическое значение, указывающее на успех
  3. Вернуться сообщение об ошибке

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

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

public static List<Poll> GetPolls() 

Тогда пусть этот метод бросить Exception если что-то пойдет не так.

+3

Наличие TryGetPolls может быть полезно, если оно не может законно вернуть ничего. – Michael

+0

+1 для чистого решения –

+4

@Michael: методы «Try ...» хороши в конкретных случаях, когда что-то может пойти не так, но вам все равно (более или менее). Если он может законно вернуть ничего, он должен вернуть null/Nothing. – STW

11

Я считаю

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

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

+0

Еще лучше, используйте IList для увеличения абстракции. –

7

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

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

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

Вместо того, что вы ищете есть пара способов:

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

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

7

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

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

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

рассмотреть вопрос о повышении и обработки сообщений об ошибках с:

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

+1: Также рассмотрите возможность создания настраиваемого исключения для известного случая, когда он будет терпеть неудачу при определенных условиях. –

+0

Но вы должны бросить нечто более конкретное, чем System.Exception, которое более точно соответствует типу ошибки. –

+0

Спасибо Яну. Это означало больше как указание на то, что следует исключить какое-то исключение. Не предназначалось для того, чтобы быть буквальной копией/пастой из Wall Wall of Code. :) –

1

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

Однако, возможно, вы просто хотите вернуть «мета» информацию о попытке, и в этом случае вам просто нужен способ вернуть более одной части информации из одного вызова метода. В этом случае я предлагаю создать класс PollResponse, который содержит два свойства: Список < Опрос> Опросы и строка ErrorMessage. После чего ваш метод возвращает объект PollResponse:

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

Это как идиоматический, как оригинальный код, ИМХО. Idiomatic C# использует исключения, чтобы сообщать об ошибках, а не настраиваемые объекты с сообщениями об ошибках. –

+3

Техника Скотта здесь может быть похожа на System.Web.HttpResponse Я не думаю, что это несправедливое предположение, что обработка коллекции объектов Poll может потребовать совершенно нового объекта, который обрабатывает ошибки, языки, срок действия, уровень видимости пользователя и т. Д. –

+0

@Greg - Я думаю, что это сводится к тому, что на самом деле ошибка. Все здесь просто предполагают, что это программное исключение, но это не обязательно так. Исключение программы означает, что выполнение не может продолжаться. Исключение и ошибка - это не одно и то же. Когда пользователь пытается ввести символ в числовое поле, это ошибка, но мне не нужно бросать исключение. Возможно, в этом случае «ошибка» заключается в том, что данные опроса устарели, или, может быть, результаты не составляют до 100%. Я больше думал о том, как мне вернуть две функции из вызова функции? –

0

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

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

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

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

+0

Я согласен со всеми вашими рассуждениями, за исключением того, что во втором случае я бы использовал совет yshuditelu, а не исходный код. – Brian

+0

Я не думаю, что «редкость» - это правильная концепция. «Исключительно» более точно. Рассмотрим функцию, принимающую число как строку в качестве аргумента. Если строка не является числом, это исключительный случай, хотя и не обязательно редкий. –

11

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

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

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

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

Так что ваши подписи метода, вероятно, следует быть:

IList<Poll> GetPolls(); 

или

bool TryGetPolls(out IList<Poll> polls); 

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

+0

Грег, это отличный момент. –

+0

+1 для IList. Я тоже должен был упомянуть об этом. –

+0

Я все за абстракцию публичного API специально, если клиент не находится под вашим контролем. Но если это внутренний класс, насколько вероятно, что вы замените реализацию List в .NET Framework каким-то другим. Если это был интерфейс, который вы можете высмеивать достаточно справедливо, но класс .Net List? Как насчет принципа KISS. – softveda

2

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

public static List<Poll> GetPolls(); 

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

0

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

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

0

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

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

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

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

1

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

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

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

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

0

Я думаю, что это нормально. Я предпочел бы, хотя:

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

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

0

C# действительно должны сделать только одну вещь. Вы пытаетесь сделать три вещи с помощью этого метода. Я бы сделал, как предложили другие, и выдал исключение, если есть ошибка. Другой вариант - создать методы расширения для вашего объекта 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 
} 

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

0

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

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

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

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

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

1

Рекомендации сказать, чтобы попытаться избежать реф и 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. 
} 
0

Существует также такая картина, как видно во многих функциях Win32.

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


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

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

0

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

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 
    } 
} 

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

Смежные вопросы