C# の式

Tip

この記事は、少なくとも 1 つのプログラミング言語を既に知っており、C# を学習している開発者向けの 基礎 セクションの一部です。 プログラミングを初めて使用する場合は、最初に「 はじめ に」チュートリアルから始めてください。

別の言語から来ていますか? C# の式は、Java、C++、JavaScript と同じように機能します。 注目すべき 1 つの違いは、 += などの複合代入演算子とインクリメント演算子 ++ は C# の式であるため、より大きな式で表示できます。

は、値 (数値、文字列、参照、またはbool) を生成するためにコンパイラが評価するコードの一部です。 たとえば、 3 + 4 * 2 は整数 11に評価される式で、 total > 10true または falseに評価される式です。

最も簡単な式は、 リテラル ( 42"hello"など) と 変数名 ( total など) です。 より単純な式と演算子を組み合わせて、より複雑な式を作成します。

式とステートメント

式によって値が生成されます。 ステートメントは、プログラムが実行する完全な命令です。 多くのステートメントには式が含まれています。 たとえば、 int total = 3 + 4 * 2; は変数宣言ステートメントです。 コンパイラは初期化子式 3 + 4 * 2を評価し、 11を生成し、その値を新しい変数 totalに割り当てます。

語句のような式と、完全な文のような C# ステートメント を考えることができます。 これらの作業定義は、C# について詳しく学習するときに遭遇する正式な用語と説明を理解するのに役立ちますが、通常のコーディングでは、区別を意識して覚える必要はほとんどありません。

式の結合

式を組み合わせることができます。 3 + 4 * 2を検討してください。 この単一式には、実際には、乗算式4 * 2加算式3 + <result>という 2 つの小さなが含まれています。 式を組み合わせる場合、C# は最初に評価するルールを決定する必要があります。 この規則は 演算子の優先順位です

完全な優先順位階層を記憶する必要はありません。 次のセクションでは、日常的なグループの概要を示します。かっこを使用すると、わからないときに順序を明示的にすることができます。

演算子の優先順位

演算子の優先順位 は、結合された式をサブ式に グループ化 する方法を決定します。 この概念は、数学クラスの演算順序ルールに似ています。 優先順位の高い演算子は、オペランド により厳密にバインド されます。 式は、これらのオペランドがまとめて括弧で囲まれているかのように構成されます。 3 + 4 * 2では、*+よりも優先順位が高いので、式は(3 + 4) * 2ではなく3 + (4 * 2)としてグループ化されます。

C# には、ここで要約した 4 つよりも優先順位の高いグループがあります。 これらの追加グループでは、加算前の乗算など、使い慣れたルールが適用され、演算子の完全なセットがカバーされます。 次のグループは、日常のコードで最も頻繁に発生する内容について説明します。

  1. プライマリ、単項、および範囲 — これらは 3 つの異なる優先順位グループであり、いずれも算術よりも厳密にバインドされます。 この概要では、実用的な目的のために、すべて算術演算の前に適用されるため、それらを 1 つのステップに結合します。
    • プライマリ 演算子 — メンバー アクセス (x.y)、メソッド呼び出し (f())、インデックス作成 (a[i])、null 条件付きアクセス (?.?[]) は、最も厳密にバインドされます。
    • 単項 演算子は、否定 (-x)、論理 NOT (!flag)、プレフィックスインクリメント (++i)、および後置インクリメント (i++) の 1 つのオペランドに対して動作します。
    • range 演算子 (..) は、array[1..4]などのスライス式のインデックス範囲を作成します。
  2. 算術*/+ は、- および % よりも強く結合されます。 乗算と除算は加算と減算の前に行われます。
  3. 比較<><=>===!= は算術よりも厳密にバインドされないため、比較の前に算術が完了します。
  4. 論理&&|| は、一般的な演算子の中で最も厳密にバインドされないため、論理の組み合わせの前に比較が完了します。

この優先順位は、式 score + bonus > threshold && attempts < maxAttempts 読んだとおりに評価されます。 scorebonusを追加し、合計を thresholdと比較し、 attemptsmaxAttemptsを比較してから、2 つの bool の結果を &&と組み合わせます。 すべてのグループ化を明示的にするためのかっこを追加すると、同じ構造 ( ((score + bonus) > threshold) && (attempts < maxAttempts)) が示されます。

すべての演算子をカバーする完全な優先順位階層については、 C# 演算子と式に関するセクションを参照してください。

意図を明確にするために括弧を使ってください

かっこを使うと、優先順位を上書きすると同時に、意図を明確に示せます。 上記のグループでは順序が明確でない場合は、括弧を追加します。

int score = 80;
int bonus = 15;
int threshold = 90;
bool eligible = true;

// Without parentheses: || binds less tightly than &&, so this reads as:
//   eligible && (score + bonus > threshold) || bonus > 20
bool result1 = eligible && score + bonus > threshold || bonus > 20;

// With parentheses: forces the || to combine two complete conditions
bool result2 = (eligible && score + bonus > threshold) || bonus > 20;

Console.WriteLine(result1); // => True
Console.WriteLine(result2); // => True

// Parentheses can also change the result:
bool isAdmin = false;
bool isOwner = true;

// Without: && binds tighter, so: (isAdmin && isOwner) || true
bool access1 = isAdmin && isOwner || true;
// With: forces the || to run first
bool access2 = isAdmin && (isOwner || true);

Console.WriteLine(access1); // => True   (false && true is false; false || true is true)
Console.WriteLine(access2); // => False  (false && anything is false)

最後の2行は、括弧によってスタイルだけでなく結果も変わることを示しています。 &&||が一緒に表示されたら、かっこを追加して、最初に結合する条件をスペル アウトします。 (isAdmin && isOwner) || isSuperUserを見た読者は、その意図がすぐに分かります。

式の評価方法

C# が結合された式を評価する方法を理解する方が、例え方が簡単です。 鉛筆と紙の複雑な数学の問題を考えてみましょう。最も内側または最も優先順位の高いサブ式を特定し、その中間値を計算し、結果を書き留めてから、次のサブ式で繰り返します。最後の答えに到達するまで続けます。

C# は同じプロセスに従い、次の 2 つの規則に従います。

ルール 1: オペランドは左から右に評価されます。 任意のバイナリ式の場合、演算子を適用する前に、両方のオペランドを完全に評価する必要があります。 C# では、最初に左オペランドが評価され、次に右が評価され、次に演算が実行されます。

ルール 2: 一部の演算子は短絡します。 特定の演算子は、結果が決定されるとすぐに評価を停止し、残りのオペランドはスキップします。

  • &&(条件 AND): 左側がfalseされるとすぐにfalseを返します。 右側は評価されません。
  • ||(条件付き OR): 左側がtrueされるとすぐにtrueを返します。 右側は評価されません。
  • ?: (条件/三項): 条件に一致する分岐のみを評価します。もう一方の分岐は評価されません。
  • ?. (null 条件付きメンバー アクセス) と ?[] (null 条件付き要素アクセス): 左側が null の場合は、メンバー アクセスまたはインデックス アクセスをスキップし、直ちに null を返します。
  • ??= (null 結合割り当て): 左側が nullされている場合にのみ、右側を割り当てます。

紙と鉛筆の評価

式の 3 + 6 / 2について考えてみましょう。 加算は読み取り順に最初に表示されますが、 /+よりも優先順位が高いので、 6 / 2 は最初に評価されるサブ式です。 紙に書くのとまったく同じように、段階的に作業します。

3 + 6 / 2
      ↓   (evaluate 6 / 2 → 3)
3 +   3
  ↓   (evaluate 3 + 3 → 6)
  6
// 3 + 6 / 2
// Step 1: 6 / 2 has higher precedence → interim value 3
// Step 2: 3 + 3 → final result 6
int result = 3 + 6 / 2;
Console.WriteLine(result); // => 6

6 / 2によって生成3中間値が+の右オペランドになり、最終的な結果が6されます。 各サブ式は中間値を生成します。これらの中間値は、1 つの値だけが残るまで、次のサブ式をフィードします。

結合規則 は関連する概念です。2 つの演算子の優先順位が同じ場合、結合規則によってどちらが先に行くかが決定されます。 ほとんどの C# 演算子は 左結合 であり、左から右へ結合されます。 そのため、a - b - ca - (b - c)ではなく、(a - b) - cと同じです。

短絡評価の実際

短絡評価は、null チェックに特に役立ちます。

string? text = null;

// Safe: second condition runs only when text is not null
bool hasContent = text != null && text.Length > 0;
Console.WriteLine(hasContent); // => False  (short-circuits after null check; no NullReferenceException)

text = "hello";
hasContent = text != null && text.Length > 0;
Console.WriteLine(hasContent); // => True

// || short-circuits on true: right side is never evaluated when left side is true
string word = "hello";
bool anyMatch = word.StartsWith("h") || word.StartsWith("x");
Console.WriteLine(anyMatch); // => True  (right side never evaluated)

// ?. short-circuits on null: returns null without accessing .Length
string? maybeNull = null;
int? length = maybeNull?.Length;   // length is null; no NullReferenceException
Console.WriteLine(length.HasValue); // => False

text != null && text.Length > 0 2 番目の条件は、 textnullされていない場合にのみ実行されるため、安全です。 同様に、?.null参照が検出されると評価が停止されるため、明示的なifチェックなしでNullReferenceExceptionを回避できます。

null セーフ演算子の詳細については、「 C# null 演算子」を参照してください。

こちらも参照ください