Подтвердить что ты не робот

Можно ли использовать оператор? и выбросить новое исключение()?

У меня есть ряд методов:

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();

но он генерирует ошибку компиляции.

Можно ли переписать мой код или есть только один способ сделать это?

4b9b3361

Ответ 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();

Нет необходимости в другом.