書かれているステートメントは、次のように書き直せば改善される可能性があります....
good = m_seedsfilter==0 ? true :
m_seedsfilter==1 ? newClusters(Sp) :
newSeed(Sp);
...しかし、一般的には、三項ステートメントに慣れる必要があります。最初に投稿されたコード、xanatos のバージョン、または私のバージョンのいずれについても、本質的に悪いことは何もありません。三項ステートメントは悪いものではなく、言語の基本的な機能であり、一度慣れると、このようなコード (元の投稿に書かれたものではなく、私が投稿したもの) の方が実際には簡単であることに気付くでしょう。 if-else ステートメントのチェーンよりも読み取ります。たとえば、このコードでは、このステートメントを次のように単純に読み取ることができgood
ます。m_seedsfilter==0
true
m_seedsfilter==1
newClusters(Sp)
newSeed(Sp)
上記の私のバージョンでは、変数 への 3 つの個別の代入が回避されgood
、ステートメントの目的が に値を代入することであることが明確になっていることに注意してくださいgood
。また、このように書くと、本質的にこれが「スイッチ ケース」構造であり、デフォルト ケースが であることが明確になりますnewSeed(Sp)
。
operator!()
の型がm_seedsfilter
オーバーライドされない限り、上記の私の書き直しは有効であることに注意してください。そうであれば、これを使用して元のバージョンの動作を維持する必要があります...
good = !m_seedsfilter ? true :
m_seedsfilter==1 ? newClusters(Sp) :
newSeed(Sp);
...そして、以下の xanatos のコメントが証明しているように、メソッドnewClusters()
とnewSeed()
メソッドが互いに異なる型を返し、それらの型が慎重に作成された無意味な変換演算子で記述されている場合は、元のコード自体に戻す必要があります (ただし、元の投稿とまったく同じ動作を忠実に再現するために、xanatos 自身の投稿のように、より適切にフォーマットされることを願っています。しかし、現実の世界では誰もそんなことをするつもりはないので、上記の最初のバージョンで問題ないはずです。
更新、元の投稿/回答から2年半後:@TimothyShieldsと私がこれについて時々賛成票を集め続けているのは興味深いことです.Timの答えは、多かれ少なかれ、この答えの賛成票の約50%で一貫して追跡しているようです. (この更新の時点で 43 対 22)。
3 項ステートメントを慎重に使用した場合に追加できる明快さの例をもう 1 つ追加したいと思います。以下の例は、コールスタック使用状況アナライザー (コンパイルされた C コードを分析するツールですが、ツール自体は C# で記述されています) 用に書いていたコードの短いスニペットです。3 つの亜種はすべて、少なくとも外部から見える効果に関する限り、まったく同じ目的を達成します。
1. 三項演算子なし:
Console.Write(new string(' ', backtraceIndentLevel) + fcnName);
if (fcnInfo.callDepth == 0)
{
Console.Write(" (leaf function");
}
else if (fcnInfo.callDepth == 1)
{
Console.Write(" (calls 1 level deeper");
}
else
{
Console.Write(" (calls " + fcnInfo.callDepth + " levels deeper");
}
Console.WriteLine(", max " + (newStackDepth + fcnInfo.callStackUsage) + " bytes)");
2. 三項演算子を使用して、Console.Write() を個別に呼び出します。
Console.Write(new string(' ', backtraceIndentLevel) + fcnName);
Console.Write((fcnInfo.callDepth == 0) ? (" (leaf function") :
(fcnInfo.callDepth == 1) ? (" (calls 1 level deeper") :
(" (calls " + fcnInfo.callDepth + " levels deeper"));
Console.WriteLine(", max " + (newStackDepth + fcnInfo.callStackUsage) + " bytes)");
3. 三項演算子を使用して、Console.Write() への単一の呼び出しに折りたたまれます。
Console.WriteLine(
new string(' ', backtraceIndentLevel) + fcnName +
((fcnInfo.callDepth == 0) ? (" (leaf function") :
(fcnInfo.callDepth == 1) ? (" (calls 1 level deeper") :
(" (calls " + fcnInfo.callDepth + " levels deeper")) +
", max " + (newStackDepth + fcnInfo.callStackUsage) + " bytes)");
上記の 3 つの例の違いは些細なことだと主張する人もいるかもしれません。簡潔にすることがすべてです。アイデアを「できるだけ少ない言葉」で表現することで、私がアイデアの最後にたどり着くまでに、聞き手/読者がアイデアの始まりを思い出すことができます。小さな子供たちと話すときは、簡単で短い文章を使うので、アイデアを表現するのに多くの文章が必要になります。私の言語に堪能な大人と話すとき、私はアイデアをより簡潔に表現する、より長く、より複雑な文を使用します。
これらの例では、1 行のテキストを標準出力に出力します。それらが実行する操作は単純ですが、より大きなシーケンスのサブセットとしてそれらを想像するのは簡単です。そのシーケンスのサブセットをより簡潔に明確に表現できればできるほど、そのシーケンスのより多くをエディターの画面に収めることができます。もちろん、私は簡単にその努力をやりすぎてしまい、理解するのが難しくなります。目標は、理解可能であることと簡潔であることの間の「スイートスポット」を見つけることです。私は、プログラマーが三項ステートメントに慣れると、それらを使用するコードを理解することは、使用しないコードを理解することよりも容易になると主張します (例えば、上記の2と3と上記の1 )。
経験豊富なプログラマーが 3 項ステートメントを快適に使用できる最後の理由は、メソッド呼び出しを行うときに不要な一時変数を作成しないようにするためです。その例として、上記の例の 4 番目の変形を提示します。ロジックはConsole.WriteLine()
;への単一の呼び出しに凝縮されています。結果はわかりにくく、簡潔ではあり ません。
4. 三項演算子なしで、Console.Write() への単一の呼び出しに折りたたまれます。
string tempStr;
if (fcnInfo.callDepth == 0)
{
tempStr = " (leaf function";
}
else if (fcnInfo.callDepth == 1)
{
tempStr = " (calls 1 level deeper";
}
else
{
tempStr = " (calls " + fcnInfo.callDepth + " levels deeper";
}
Console.WriteLine(new string(' ', backtraceIndentLevel) + fcnName + tempStr +
", max " + (newStackDepth + fcnInfo.callStackUsage) + " bytes)");
「ロジックを単一の呼び出しに凝縮することConsole.WriteLine()
は不要である」と主張する前に、これは単なる例であると考えてください。複数のパラメーターを取り、他の変数の状態に基づいた一時的なパラメーターを必要とする他のメソッドの呼び出しを想像してみてください。独自の一時変数を作成してそれらの一時変数でメソッド呼び出しを行うか、または三項演算子を使用してコンパイラに独自の (名前のない) 一時変数を作成させることができます。繰り返しますが、三項演算子を使用すると、使用しない場合よりもはるかに簡潔でわかりやすいコードが可能になると主張します。しかし、理解できるようにするためには、三項演算子が悪であるという先入観を捨てなければなりません。