Подтвердить что ты не робот

Лучшая практика использования ключевого слова "out" в С#

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

Иногда я вижу некоторые подписи методов, которые выглядят так:

public decimal CalcSomething(Date start, Date end, out int someOtherNumber){}

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

public Result CalcSomething(Date start, Date end){}

где результат - это тип, который содержит десятичное число и некоторое другое число. Я думаю, что это облегчает чтение. Это позволяет продлить результат или добавить свойства без нарушения кода. Это также означает, что вызывающему устройству этого метода не нужно объявлять локальный облачный "someOtherNumber" перед вызовом. Из ожиданий использования не все абоненты будут заинтересованы в "someOtherNumber".

В отличие от этого, единственные экземпляры, которые я могу представить прямо сейчас в рамках .Net, где параметры "out" имеют смысл, - это методы, подобные TryParse(). Это на самом деле заставляет вызывающего абонента писать более простой код, в котором вызывающий пользователь в первую очередь будет интересоваться параметром out.

int i;
if(int.TryParse("1", i)){
  DoSomething(i);
}

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

Мысли?

4b9b3361

Ответ 1

Существует одна причина, по которой один из правил статического анализа кода (= FxCop) указывает на вас, когда вы используете параметры out. Я бы сказал: используйте только out, когда это действительно необходимо в сценариях типа interop. Во всех остальных случаях просто не используйте out. Но возможно, что только я?

Ответ 2

Это то, что . Руководство разработчика .NET Framework должно говорить о параметрах:

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

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

Но если вы используете их:

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

Это соглашение делает метод подпись легче понять.

Ответ 3

Ваш подход лучше, чем вне, потому что вы можете "цеплять" так:

DoSomethingElse(DoThing(a,b).Result);

в отличие от

DoThing(a, out b);
DoSomethingElse(b);

Методы TryParse, реализованные с "out", были ошибкой, IMO. Это было бы очень удобно в цепочках.

Ответ 4

Есть только очень мало случаев, когда я использовал бы out. Один из них - если ваш метод возвращает две переменные, которые из точки OO не входят в объект вместе.

Если, например, вы хотите получить наиболее распространенное слово в текстовой строке и 42-е слово в тексте, вы можете вычислить их как в одном методе (нужно разобрать текст только один раз). Но для вашего приложения эти данные не имеют никакого отношения друг к другу: вам нужно наиболее распространенное слово для статистических целей, но вам нужно всего лишь 42-е слово, потому что ваш клиент является geeky поклонником Douglas Adams.

Да, этот пример очень надуман, но у меня нет лучшего...

Ответ 5

Держитесь подальше от out. Это там как низкоуровневое удобство. Но на высоком уровне это анти-техника.

int? i = Util.TryParseInt32("1");
if(i == null)
    return;
DoSomething(i);

Ответ 6

Одно из преимуществ out заключается в том, что компилятор проверяет, что CalcSomething действительно присваивает значение someOtherNumber. Он не будет проверять, что поле someOtherNumber для Result имеет значение.

Ответ 7

Если вы даже видели и работали с MS пространство имен System.Web.Security

MembershipProvider 
   public abstract MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status);

Вам понадобится ведро. Это пример класса, разбивающего многие парадигмы дизайна. Ужасно!

Просто потому, что язык имеет параметры, это не значит, что они должны использоваться. например goto

Использование out. Похоже, что Dev был либо ленив, чтобы создать тип, либо захотел попробовать функцию языка. Даже полностью надуманный пример MostCommonAnd42ndWord выше я бы использовал Список или новый тип contrivedresult с двумя свойствами.

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

Ответ 8

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

Один важный момент, однако, что james curran также указал, что компилятор обеспечивает назначение значения. Это общий шаблон, который я вижу на С#, что вы должны явно указать определенные вещи для более читаемого кода. Другим примером этого является ключевое слово переопределения, которого у вас нет в Java.

Ответ 9

Если ваш результат более сложный, чем одно значение, вы должны, если возможно, создать объект результата. Причины, я должен сказать это?

  • Весь результат инкапсулирован. То есть у вас есть один пакет, который информирует код полного результата CalcSomething. Вместо того, чтобы внешний код интерпретировать значение десятичного значения, вы можете указать свойства для вашего предыдущего возвращаемого значения, ваше значение someOtherNumber и т.д.

  • Вы можете включить более сложные показатели успеха. Вызов, который вы написали, может вызвать исключение, если конец до начала, но исключение - единственный способ сообщить об ошибках. Используя объект результата, вы можете включить логическое или перечисляемое значение "Успех" с соответствующим сообщением об ошибках.

  • Вы можете отложить выполнение результата до фактического изучения поля "результат". То есть выполнение любых вычислений не должно выполняться до тех пор, пока вы не будете использовать значения.