33

次に行う方法はいくつかあります。

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つしかありませんか?

4

5 に答える 5

62

C#7の場合

C#7ではthrow式になるため、質問で説明されているコードを正確に使用することは問題ありません。

C#6以前の場合

C#6以前では直接それを行うことはできません-??の2番目のオペランド throwステートメントではなく、式である必要があります。

簡潔なオプションを本当に見つけようとしている場合は、いくつかの選択肢があります。

あなたは書くことができます:

public static T ThrowException<T>()
{
    throw new Exception(); // Could pass this in
}

その後:

return command.ExecuteScalar() as int? ?? ThrowException<int?>();

私はあなたがそうすることを本当にお勧めしません...それはかなり恐ろしくて一義的です。

拡張メソッドはどうですか?

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?タイプ引数として指定できないため、やや醜いです...

于 2009-11-19T11:54:02.810 に答える
9

言われているように、あなたは??でこれを行うことはできません オペレーター(まあ、これをよりきれいにするというあなたの目的に合わないように見えるいくつかのゆがみがないわけではありません)。

このパターンが出現しているのを見ると、すぐに施行について考えます。もともとはC++の世界から、C#にかなりうまく移行しますが、ほとんどの場合、それほど重要ではありません。

アイデアはあなたが形の何かを取るということです:

if( condition )
{
  throw Exception;
}

そしてそれを次のように変換します:

Enforce<Exception>( condition );

(例外タイプをデフォルトにすることで、さらに単純化できます)。

さらに進んで、さまざまな条件チェック用のNunitスタイルのメソッドのセットを作成できます。

Enforce<Exception>.NotNull( obj );
Enforce<Exception>.Equal( actual, expected );
Enforce<Exception>.NotEqual( actual, expected );

または、期待ランバを提供することでさらに良い:

Enforce<Exception>( actual, expectation );

本当に素晴らしいのは、それを実行したら、実際のパラメータを返し、インラインで適用できることです。

return Enforce( command.ExecuteScalar() as Int32?, (o) => o.HasValue ).Value;

...そしてこれはあなたが求めているものに最も近いようです。

私は以前にこれの実装をノックアップしました。引数を取る例外オブジェクトを一般的に作成する方法のように、いくつかの小さな問題があります-そこにいくつかの選択肢があります(私は当時リフレクションを選択しましたが、追加のパラメーターとしてファクトリを渡す方がさらに良いかもしれません)。しかし、一般的に、それはすべて非常に簡単で、多くのコードを本当にクリーンアップすることができます。

オープンソースの実装をノックアップするためにやるべきことのリストにあります。

于 2009-11-19T12:35:31.053 に答える
4

戻り値がそうでないときに例外が必要な場合は、次のInt32ようにします。

return (int)command.ExecuteScalar();

独自のカスタム例外をスローしたい場合は、代わりに次のようなことを行います。

int? result = command.ExecuteScalar() as int?;
if (result == null) throw new YourCustomException();
return result.Value;
于 2009-11-19T11:54:05.460 に答える
2

null合体演算子の右側で例外をスローすることはできません。この背後にある理由は、演算子の右側がステートメントではなく式である必要があるためです。

null合体演算子は次のように機能します。演算子の左側の値がnullの場合は、それを返します。それ以外の場合は、演算子の右側にあるものを返します。throwキーワードは値を返しません。したがって、演算子の右側では使用できません。

于 2009-11-19T11:54:19.253 に答える
1

あなたができない理由:

return command.ExecuteScalar() as Int32? ?? throw new Exception();

例外をスローするのはステートメントであり、式ではないためです。

コードを少し短くしたいだけなら、おそらくこれは:

var result = command.ExecuteScalar() as Int32?;
if(result.HasValue) return result;
throw new Exception();

他の必要はありません。

于 2009-11-19T11:56:08.123 に答える