Каково стандартное поведение для параметра out, когда метод TryXxxx возвращает false? - PullRequest
5 голосов
/ 15 марта 2010

Принимая метод со следующей подписью

bool TryXxxx(object something, out int toReturn)

Что допустимо для toReturn, если TryXxxx возвращает false?

В том смысле, что toReturn никогда не должен использоваться, если TryXxxx терпит неудачу, имеет ли это значение?

Если бы toReturn был обнуляемым типом, то имело бы смысл возвращать нуль. Но int не может быть обнуляемым, и я не хочу заставлять его.

Если toReturn всегда определенное значение, если TryXxxx не удается, мы рискуем иметь позицию, в которой 2 значения могут рассматриваться как одно и то же. Я вижу, что это может привести к возможной путанице, если значение «по умолчанию» будет возвращено как правильный ответ (когда TryXxxx возвращает true).

Если с точки зрения реализации это выглядит так, что toReturn быть значением [ny] проще всего, но есть ли что-то более важное, что стоит рассмотреть?

Ответы [ 6 ]

6 голосов
/ 15 марта 2010

Я бы явно задокументировал бы его, используя значение по умолчанию для типа (каким бы ни был этот тип; поэтому 0 в этом случае, но default(T) в более общем случае). Существуют различные случаи, когда значение по умолчанию - это именно то, что вы хотите, если значение отсутствует - и в этом случае вы можете просто игнорировать возвращаемое значение из метода.

Обратите внимание, что это то, что делают методы типа int.TryParse и Dictionary.TryGetValue.

4 голосов
/ 15 марта 2010

Это может быть default(int):

bool TryXxxx(object something, out int toReturn)
{
    toReturn = default(int);
    return false;
}
2 голосов
/ 15 марта 2010

В основном это что-то. Я бы задокументировал это как «не определено». Разумные значения:

  • по умолчанию ()
  • Minvalue, MaxCValue, NEWvalue (как новый int ()), ноль
  • значение NAN (Double.NaN)

Но, в общем, я действительно говорю «не определено» и не даю людям то, на что они могут положиться.

2 голосов
/ 15 марта 2010

Я бы сказал default, но на самом деле это не должно иметь значения. Соглашение с TryX заключается в том, что вызывающая сторона должна проверять возвращаемое значение и использовать параметр out только тогда, когда метод возвращает true.

0 голосов
/ 02 февраля 2013

До .net нормальный шаблон был для TryXX методов, которые просто оставляли переданный по ссылке аргумент неизмененным. Это был очень полезный шаблон, так как это означало, что код, который хотел использовать значение по умолчанию, мог сделать что-то вроде:

MyNum = 5;
TryParsing(myString, &myNum);

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

if (TryParsing(myString, &myNum))
{ .. code that uses myNum .. }
else
{ .. code that doesn't use myNum .. }

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

Однако

C # не очень хорошо допускает такой шаблон, если только TryParsing не написан на другом языке. Либо TryParsing должен быть записан таким образом, чтобы предыдущее значение myNum было безусловно перезаписано без проверки, вызывающий должен безоговорочно инициализировать его, либо для двух сценариев должны быть предусмотрены разные методы. Если бы метод TryParsing был написан на каком-то другом языке, он теоретически мог бы вести себя как методы старого стиля (записать аргумент в случае успеха и оставить его в покое, если нет), при этом все еще называя его параметром out. Однако я не рекомендовал бы это, потому что причудливое поведение не ограничивалось бы этим out параметром.

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

fooStruct(string st)
{
  fooStruct.TryParse(st, out this);
}

Компилятор был бы совершенно доволен таким конструктором, поскольку он "определенно" пишет this. С другой стороны, если какой-то другой код делает:

while(someCondition)
{
  var s = new fooStruct(someString);
  ...
}

Можно ожидать, что s будет содержать инициализированную структуру (если someString допустимо) или будет пустым (если это не так). Ничто в этом коде не предполагает, что s может сохранять свое значение между повторениями цикла. Тем не менее, это именно то, что могло бы произойти.

0 голосов
/ 15 марта 2010

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

2) Однако в таких случаях я всегда ссылаюсь на реализацию в .NET Framework, чтобы гарантировать согласованность. И быстрый просмотр Reflector показывает, что тип Int32 возвращает 0, если синтаксический анализ не удался:

internal static unsafe bool TryParseInt32(string s, NumberStyles style, NumberFormatInfo info, out int result)
{
    byte* stackBuffer = stackalloc byte[1 * 0x72];
    NumberBuffer number = new NumberBuffer(stackBuffer);
    result = 0; // <== see here!
    if (!TryStringToNumber(s, style, ref number, info, false))
    {
        return false;
    }
    if ((style & NumberStyles.AllowHexSpecifier) != NumberStyles.None)
    {
        if (!HexNumberToInt32(ref number, ref result))
        {
            return false;
        }
    }
    else if (!NumberToInt32(ref number, ref result))
    {
        return false;
    }
    return true;
}

Однако, не зная подробностей реализации, все же может случиться так, что проблема синтаксического анализа возникает, когда значение уже было присвоено (частично). В этом случае значение может перестать быть 0. Поэтому вы всегда должны придерживаться «решения» 1)! : -)

gehho.

...