Когда следует использовать параметры?

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

Я видел такой метод,

   public void Do(int arg1, int arg2, out int result)

Есть ли случаи, когда это действительно имеет смысл?

как насчет TryParse, почему бы не вернуть тип ParseResult? или в новой структуре возвращают нулевой способ?

Ответ 1

Выход хорош, если у вас есть функция TryNNN, и ясно, что параметр out всегда будет установлен, даже если функция не будет выполнена. Это позволяет полагаться на то, что локальная переменная, которую вы объявляете, будет установлена ​​вместо того, чтобы помещать проверки позже в вашем коде с нулевым значением. (Комментарий ниже указывает, что параметр может быть установлен на null, поэтому вы можете проверить документацию для функции, которую вы вызываете, чтобы убедиться, что это так или нет.) Это делает код немного понятным и легче читать. Другой случай - когда вам нужно вернуть некоторые данные и статус в состояние метода, например:

public bool DoSomething(int arg1, out string result);

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

Недостатком является то, что вы должны объявить локальную переменную, чтобы использовать их:

string result;
if (DoSomething(5, out result))
    UpdateWithResult(result);

Вместо:

UpdateWithResult(DoSomething(5));

Однако это может даже не быть недостатком, это зависит от дизайна, который вы собираетесь использовать. В случае DateTime предоставляются оба средства (Parse и TryParse).

Ответ 2

Ну, как и в большинстве случаев, это зависит. Давайте посмотрим на варианты

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

В случае TryParse эффективное использование параметра out - вам не нужно создавать новый тип, который был бы 16B накладных расходов (на 32-битных машинах), или повлечь за собой полную стоимость их сбора мусора после вызова. Например, TryParse может быть вызван из цикла, поэтому здесь правило params. Для функций, которые не будут вызываться в цикле (т.е. Производительность не является серьезной проблемой), возврат одного составного объекта может быть "более чистым" (субъектом наблюдателя). Теперь с анонимными типами и динамической типизацией это может стать еще проще.

Примечание:

  • out params имеют некоторые правила, которым необходимо следовать, то есть компилятор гарантирует, что функция инициализирует значение до его выхода. Таким образом, TryParse должен установить параметр out для некоторого значения, даже если операция анализа не выполнена.
  • Шаблон TryXXX - хороший пример того, когда следует использовать параметры - Int32.TryParse был введен, потому что люди жаловались на перфоманс хитов исключений, чтобы узнать, не удалось ли выполнить синтаксический анализ. Кроме того, наиболее вероятная вещь, которую вы могли бы сделать, если бы синтаксический анализ удался, заключается в получении анализируемого значения - использование параметра out означает, что вам не нужно делать другой вызов метода в Parse

Ответ 3

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

bool isValid = int.TryParse("100", out int result = 0);

Ответ 4

Определенно, параметры out предназначены для использования, когда у вас есть метод, которому нужно вернуть более одного значения, в приведенном выше примере:

public void Do(int arg1, int arg2, out int result)

Не имеет смысла использовать параметр out, так как вы возвращаете только одно значение, и этот метод можно использовать лучше, если вы удалите параметр out и поместите значение возврата int:

public int Do(int arg1, int arg2)

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

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

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

Ответ 5

Несколько лет спустя с ответом, я знаю. out (и ref) также очень полезен, если вы не хотите, чтобы ваш метод создавал экземпляр нового объекта для возврата. Это очень актуально в высокопроизводительных системах, где вы хотите добиться производительности в микромикросе для вашего метода. создание экземпляров относительно дорого, с точки зрения доступа к памяти.

Ответ 6

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

Параметры вывода могут использоваться как симиплер.

Ответ 7

Да, это имеет смысл. Возьмите это, например.

String strNum = "-1";
Int32 outNum;

if (Int32.TryParse(strNum, out outNum)) {
    // success
}
else {
    // fail
}

Что вы могли бы вернуть, если операция завершилась неудачно в нормальной функции с возвращаемым значением? Вы, конечно же, не смогли бы вернуть -1, чтобы представить сбой, потому что тогда не было бы никакого различия между значением возврата к ошибке и фактическим значением, которое начиналось с начала. Вот почему мы возвращаем логическое значение, чтобы увидеть, удалось ли ему это сделать, и если бы это было сделано, мы уже получили бы наше "возвращаемое" значение.

Ответ 8

Меня раздражает, что я не могу передать значение null в параметр out для функций TryParse.

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

Ответ 9

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

StatusInfo a, b, c;

Initialize(out a);
Validate(a, out b);
Process(b, out c);

против.

StatusInfo a = Initialize();
StatusInfo b = Validate(a);
StatusInfo c = Process(b);

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

Ответ 10

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

Как сказано здесь, одним типичным вариантом использования является метод TrySomething, в котором вы хотите вернуть bool в качестве индикатора успеха, а затем фактическое значение. Я также считаю, что немного чище в if-statement - все три варианта примерно одинаковы для LOC.

int myoutvalue;
if(int.TryParse("213",out myoutvalue){
    DoSomethingWith(myoutvalue);
}

vs.

ParseResult<int> myoutvalue = int.TryParse("213");
if ( myoutvalue.Success ) {
    DoSomethingWith(myoutvalue.Value);
}

vs.

int? myoutvalue = int.TryParse("213");
if(myoutvalue.HasValue){
    DoSomethingWith(myoutvalue.Value);
}

Что касается "Почему бы не вернуть Nullable Type": TryParse существует с Framework 1.x, тогда как Nullable Types - с 2.0 (поскольку они требуют Generics). Так почему же небрежно нарушать совместимость или начинать вводить несоответствия между TryParse на некоторых типах? Вы всегда можете написать свой собственный метод расширения для дублирования уже существующих функций (см. Eric Lipperts Post о несвязанной теме, которая включает некоторые аргументы в пользу выполнения/не делать вещи)

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