Можно ли использовать оператор? и выбросить новое исключение()?
У меня есть ряд методов:
var result = command.ExecuteScalar() as Int32?;
if(result.HasValue)
{
return result.Value;
}
else
{
throw new Exception(); // just an example, in my code I throw my own exception
}
Хотел бы я использовать оператора ??
как это:
return command.ExecuteScalar() as Int32? ?? throw new Exception();
но он генерирует ошибку компиляции.
Можно ли переписать мой код или есть только один способ сделать это?
Ответы
Ответ 1
Для С# 7
В С# 7 выражение throw
становится выражением, поэтому следует точно использовать код, описанный в вопросе.
Для С# 6 и более ранних
Вы не можете сделать это непосредственно в С# 6 и ранее - второй операнд? должно быть выражением, а не выражением throw.
Есть несколько альтернатив, если вы действительно просто пытаетесь найти вариант, который является кратким:
Вы можете написать:
public static T ThrowException<T>()
{
throw new Exception(); // Could pass this in
}
И затем:
return command.ExecuteScalar() as int? ?? ThrowException<int?>();
Я действительно не рекомендую вам это делать, хотя... это довольно ужасно и unidiomatic.
Как насчет метода расширения:
public static T ThrowIfNull(this T value)
{
if (value == null)
{
throw new Exception(); // Use a better exception of course
}
return value;
}
Тогда:
return (command.ExecuteScalar() as int?).ThrowIfNull();
Еще одна альтернатива (опять-таки метод расширения):
public static T? CastOrThrow<T>(this object x)
where T : struct
{
T? ret = x as T?;
if (ret == null)
{
throw new Exception(); // Again, get a better exception
}
return ret;
}
Позвонить с помощью:
return command.ExecuteScalar().CastOrThrow<int>();
Это несколько уродливо, потому что вы не можете указать int?
как аргумент типа...
Ответ 2
Как уже было сказано, вы не можете сделать это с помощью оператора (ну, не без каких-либо искажений, которые, похоже, не соответствуют вашей цели сделать это чище).
Когда я вижу этот шаблон, я сразу думаю о Прикрепления. Первоначально из мира С++ они очень хорошо переносятся на С#, хотя они, вероятно, менее важны большую часть времени.
Идея состоит в том, что вы берете что-то вроде формы:
if( condition )
{
throw Exception;
}
и преобразует его в:
Enforce<Exception>( condition );
(вы можете дополнительно упростить, по умолчанию тип исключения).
Взяв его дальше, вы можете написать набор методов стиля Nunit для различных проверок условий, например.
Enforce<Exception>.NotNull( obj );
Enforce<Exception>.Equal( actual, expected );
Enforce<Exception>.NotEqual( actual, expected );
и др.
Или, еще лучше, предоставляя ожидающее lamba:
Enforce<Exception>( actual, expectation );
Что действительно здорово в том, что, как только вы это сделали, вы можете вернуть фактический параметр и принудительно выполнить inline:
return Enforce( command.ExecuteScalar() as Int32?, (o) => o.HasValue ).Value;
... и это, кажется, ближе всего к тому, что вы после.
Я выполнил эту задачу раньше. Там несколько маленьких мелочей, например, как вы в целом создаете объект исключения, который принимает аргументы - некоторые варианты там (я выбрал отражение в то время, но передача factory в качестве дополнительного параметра может быть еще лучше). Но в целом все это довольно просто и может реально очистить много кода.
Это в моем списке вещей, чтобы сделать, чтобы сбить реализацию с открытым исходным кодом.
Ответ 3
Если вам просто нужно исключение, когда возвращаемое значение не является Int32
, сделайте следующее:
return (int)command.ExecuteScalar();
Если вы хотите создать собственное собственное исключение, я бы, вероятно, сделал бы что-то вроде этого:
int? result = command.ExecuteScalar() as int?;
if (result == null) throw new YourCustomException();
return result.Value;
Ответ 4
Вы не сможете выбросить исключение с правой стороны оператора нулевой коалесценции. Причина этого в том, что правая часть оператора должна быть выражением, а не выражением.
Оператор нулевой коалесценции работает так: если левое значение оператора равно null, верните его; в противном случае верните то, что справа от оператора. Ключевое слово throw
не возвращает значение; следовательно, его нельзя использовать в правой части оператора.
Ответ 5
Причина, по которой вы не можете сделать:
return command.ExecuteScalar() as Int32? ?? throw new Exception();
Это потому, что бросание исключения - это выражение, а не выражение.
Если вы просто хотите немного сократить код, возможно, это:
var result = command.ExecuteScalar() as Int32?;
if(result.HasValue) return result;
throw new Exception();
Нет необходимости в другом.