Я вижу следующий шаблон кода повсюду в кодовой базе моей компании (приложение .NET 3.5):
bool Foo(int barID, out Baz bazObject) {
try {
// do stuff
bazObject = someResponseObject;
return true;
}
catch (Exception ex) {
// log error
return false;
}
}
// calling code
BazObject baz = new BazObject();
fooObject.Foo(barID, out baz);
if (baz != null) {
// do stuff with baz
}
Я пытаюсь обдумать, почему вы сделали бы это вместо того, чтобы Foo
метод просто взял идентификатор и возвратил Baz
объект, вместо того, чтобы возвращать значение, которое не используется, и иметь фактический объект как параметр ref или output.
Есть ли какая-то скрытая выгода от этого стиля кодирования, который мне не хватает?
c#
code-quality
coding-style
Уэйн Молина
источник
источник
baz
будучиnull
и возвращаемыйbool
существоfalse
являются не эквивалентны.new BazObject()
никогдаnull
, поэтому, если неbazObject
будет обновлено до того, какException
будет добавленоFoo
, когдаfalse
возвращеноbaz
, никогда не будетnull
. Было бы очень полезно, если бы спецификации дляFoo
были доступны. На самом деле, это, пожалуй, самая серьезная проблема, демонстрируемая этим кодом.Ответы:
Вы обычно используете этот шаблон, чтобы написать код следующим образом:
например, он используется в CLR для TryGetValue в классе словаря. Это позволяет избежать некоторой избыточности, но параметры out и ref всегда казались мне немного беспорядочными
источник
Это старый код в стиле C, до того, как возникли исключения. Возвращаемое значение указывает, был ли метод успешным или нет, и если это так, параметр будет заполнен результатом.
В .net у нас есть исключения для этой цели. Не должно быть никаких причин следовать этой схеме.
[edit] Очевидно, что это влияет на производительность при обработке исключений. Может быть, это как-то связано с этим. Однако в этом фрагменте кода уже выдается исключение. Было бы чище просто позволить ему двигаться вверх по стеку, пока он не окажется в более подходящем месте.
источник
if (baz.Select())
но чаще всего возвращаемое значение просто выбрасывается, и значение проверяется по нулевому или некоторому свойству.Учитывая фрагмент кода, это выглядит совершенно бессмысленно. Для меня исходный шаблон кода предполагает, что для BazObject допустимым является случай null, а возврат bool является мерой безопасного определения случая сбоя. Если следующий код был:
Это будет иметь больше смысла для меня, чтобы сделать это таким образом. Возможно, это тот метод, который кто-то ранее использовал, чтобы гарантировать передачу baz по ссылке, не понимая, как на самом деле работают параметры объекта в C #.
источник
Иногда этот шаблон полезен, когда вы, вызывающая программа, не должны заботиться о том, является ли возвращаемый тип ссылочным или типом значения. Если вы вызываете такой метод для извлечения типа значения, этому типу значения потребуется либо недействительное установленное значение (например, double.NaN), либо вам нужен другой способ определения успеха.
источник
Идея состоит в том, чтобы вернуть значение, которое указывает, был ли процесс успешным, допуская такой код:
Если объект не может быть нулевым (что кажется правильным в вашем примере), лучше сделать это следующим образом:
Если объект может быть нулевым, исключения - это путь:
Это общий шаблон, используемый в C, где нет исключений. Это позволяет функции возвращать состояние ошибки. Исключения, как правило, гораздо более чистое решение.
источник