Для векторов этот поток на форумах MSDN имеет фрагмент кода для установки часов на векторном индексе, который мог бы помочь.
Мне больше нравится версия с нулевым значением, потому что вы можете использовать нулевой оператор объединения ?? на нем, например:
int reallyTerrible = 0;
var mightBeWonderful = DoSomethingWonderful() ?? reallyTerrible;
Это зависит от того, как, по вашему мнению, должен выглядеть вызывающий код. И поэтому для чего используется ваша функция.
Как правило, вам следует избегать аргументов out. С другой стороны, было бы неплохо иметь такой код:
int parameter;
if (DoSomething(out paramameter))
{
// use parameter
}
Когда у вас есть int, допускающий значение NULL, это будет выглядеть так:
int? result = DoSomething();
if (result != null)
{
// use result
}
Это несколько лучше, потому что у вас нет аргумента out, но Код, который определяет, удалось ли выполнить функцию, выглядит не очень очевидным.
Не забывайте, что есть еще один вариант: использовать Exeptions. Делайте это только в том случае, если случай, когда ваша функция не работает, действительно является исключительным и своего рода случаем ошибки.
try
{
// normal case
int result = DoSomething()
}
catch (SomethingFailedException ex)
{
// exceptional case
}
Одно из преимуществ исключения состоит в том, что вы не можете просто игнорировать его. Обычный случай также легко реализовать. Если исключительный случай можно игнорировать, использовать исключения не следует.
Изменить: Забыл упомянуть: еще одно преимущество исключения состоит в том, что вы также можете предоставить информацию , почему операция не удалась. Эта информация предоставляется типом исключения, свойствами исключения и текстом сообщения.
Я бы следовал шаблону, используемому в каком-то месте библиотеки .Net, например:
bool int.TryParse(string s, out value)
bool Dictionary.TryGetValue(T1 key, out T2 value)
Итак, я бы сказал:
public bool TryDoSomethingWonderful(out int parameter)
Это действительно зависит от того, что вы делаете.
Является ли значение null значимым ответом? Если нет, я бы предпочел вызов метода bool TryDoSomethingWonderful (out int)
. Это соответствует Framework.
Если, однако, null является значимым возвращаемым значением, возвращая int? имеет смысл.
Я бы использовал второй, потому что мне, вероятно, нужно сразу узнать, был ли вызов успешным, и в этом случае я лучше напишу
int x;
if( DoSomethingWonderful( out x ) )
{
SomethingElse(x);
}
, чем
int? x = DoSomethingWonderful();
if( x.HasValue )
{
SomethingElse(x.Value);
}
Если есть только один способ потерпеть неудачу, или если вам никогда не понадобится знать , почему это не удалось, я бы сказал, что это, вероятно, проще и легче использовать возвращаемое значение, допускающее значение NULL.
И наоборот, если существует несколько способов сбоя, и вызывающий код может захотеть точно знать, почему произошел сбой, тогда используйте параметр out и верните код ошибки вместо логического значения (альтернативно, вы можете создать исключение, но, судя по вашему вопросу, похоже, вы уже решили не генерировать исключение).
Интересно, что мое личное мнение существенно меняется в зависимости от характера метода. В частности, если цель метода - получить одно значение , в отличие от «делать что-то».
Пример:
bool GetSerialNumber(out string serialNumber)
vs
string GetSerialNumber() // returns null on failure
Второе кажется мне более «естественным», и аналогично:
bool GetDeviceId(out int id)
vs
int? GetDeviceId() // returns null on failure`
Но я признаю, что это действительно относится к сфере "стиля кодирования".
О, и я тоже склонен предпочитать выбросы исключений:
int GetDeviceId() // throws an exception on read failure
Я все еще не продан почему они так ошибаются. Можем ли мы поговорить об этом, Орен? ; -)
Лучше, чем использовать try catch. Похоже, вызывающий не знает, что может случиться?
Должны ли мы проверять и bool, и out, или я должен проверять и возвращающий null, и фактический return.
Пусть метод делает то, что должен, и в В случае сбоя, сообщите вызывающему абоненту о том, что он потерпел неудачу, а вызывающий абонент обработает запрос.
Если производительность не является основной проблемой, вы должны вернуть int
и выдать исключение в случае сбоя.
Я поддерживаю использование выходного параметра. На мой взгляд, это та ситуация, для которой использование выходных параметров наиболее подходит.
Да, вы можете использовать оператор coalesce, чтобы ваш код оставался однострочным, если и только если у вас есть альтернативное значение которые вы можете использовать в остальной части вашего кода. Я часто обнаруживаю, что для меня это не так, и я бы предпочел выполнить другой путь кода, чем если бы я смог успешно получить значение.
int value;
if(DoSomethingWonderful(out value))
{
// continue on your merry way
}
else
{
// oops
Log("Unable to do something wonderful");
if (DoSomethingTerrible(out value))
{
// continue on your not-so-merry way
}
else
{
GiveUp();
}
}
Кроме того, если значение, которое я хочу получить, действительно допускает значение NULL , то использование функции с выходным параметром и логическим возвращаемым значением, на мой взгляд, является самым простым способом определить разницу между «Мне не удалось получить значение» и «Полученное мной значение равно нулю». Иногда меня волнует это различие, например, в следующем примере:
private int? _Value;
private bool _ValueCanBeUsed = false;
public int? Value
{
get { return this._Value; }
set
{
this._Value = value;
this._ValueCanBeUsed = true;
}
}
public bool DoSomethingTerrible(out int? value)
{
if (this._ValueCanBeUsed)
{
value = this._Value;
// prevent others from using this value until it has been set again
this._ValueCanBeUsed = false;
return true;
}
else
{
value = null;
return false;
}
}
На мой взгляд, единственная причина, по которой большинство людей не используют выходные параметры, состоит в том, что они считают синтаксис громоздким. Однако я действительно считаю, что использование выходных параметров является более подходящим решением этой проблемы, и я обнаружил, что как только я привык к этому, я обнаружил, что синтаксис намного предпочтительнее возврата нулевого значения.