Лучшая практика использования ключевого слова "out" в C # - PullRequest
17 голосов
/ 05 января 2009

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

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

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

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

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

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

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

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

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

Мысли

Ответы [ 9 ]

20 голосов
/ 05 января 2009

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

15 голосов
/ 05 января 2009

Это то, что Руководство разработчика *1001* .NET говорит о наших параметрах:

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

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

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

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

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

6 голосов
/ 05 января 2009

Ваш подход лучше, чем вне, потому что вы можете «цеплять» вызовы таким образом:

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

в отличие от

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

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

4 голосов
/ 05 января 2009

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

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

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

1 голос
/ 28 ноября 2012

Если вы даже видели и работали с 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);

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

То, что в языке есть параметры, не означает, что их следует использовать. например, перейти к

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

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

1 голос
/ 05 января 2009

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

1 голос
/ 05 января 2009

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

int? i = Util.TryParseInt32("1");
if(i == null)
    return;
DoSomething(i);
0 голосов
/ 05 января 2009

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

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

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

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

0 голосов
/ 05 января 2009

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...