.NETエンジニア・プログラマ向けの技術情報・業界ニュースをお届けします。

  1. FEnet.NETナビ
  2. .NETコラム
  3. プログラミング言語
  4. C#
  5. C#のref・out・inについてわかりやすく解説!ref・out・inの違いと制約

C#のref・out・inについてわかりやすく解説!ref・out・inの違いと制約

  • C#
  • プログラミング言語
公開日時:   更新日時:
C#のref・out・inについてわかりやすく解説!ref・out・inの違いと制約
この記事でわかること
    基本情報技術者試験の試験対策はこちら>>
    システム
    エンジニア
    C#のref・out・inは何が違うのですか。
    プロジェクト
    マネージャー
    呼び出す側での初期化やメソッドでの値の代入の点で違いがあります。

    C#のref・out・inとは?


    C#にはrefやoutやinというキーワードがありますが、初心者の方はよく知らない人も多いでしょう。この記事はref・out・inについて分かりやすく解説するので是非ご覧ください。

    C#でメソッドに値を渡して、その値を操作して結果を取得する場合、以下のように行うのが普通です。

    refでフィールドをメソッドに渡すことができる

    上の結果は7になります。これを「値渡し」と言います。基本的にこのやり方でプログラミングを行っていて問題はありません。ただ、フィールドをメソッドに渡してそちらで値を操作したい時もあるかもしれません。その場合はどうしたらよいのでしょうか。

    それを実現するのがrefです。以下のC#サンプルのように使用します。

    refで参照渡しが可能になる

    上のC#サンプルを実行すると結果は7になります。前のサンプルと変わった所は、AddValueメソッドに3つ目のパラメータの「ref int c」が追加され、戻り値をreturnで返さずそのcにaとbを加算した結果を代入するようになっています。

    AddValueを呼び出す側では、加算した結果を入れる変数のsumをrefキーワードを付けてAddValueに渡しています。これでAddValue側でsumに値が代入されます。この渡し方を「参照渡し」と言います。

    フィールドを初期化せずに参照渡しするには?

    上のC#サンプルではまずsumを0で初期化していますが、その後にAddValueで値が更新されるので無意味に感じます。しかしsumの宣言を「int sum;」とすると、「ref sum」の箇所で未割り当てのローカル変数が使用されましたというエラーになります。

    初期化しないで参照渡しをする方法はないのでしょうか?それを可能にするのが、以下のC#サンプルで使用しているoutです。

    outで初期化をせず参照渡しができる

    上のC#サンプルは今までのサンプルのinをoutに変更して、sumの初期化を無くしただけです。これで今までと同じように動作します。outを使えばrefと違って渡すフィールドの初期化が不要になるということですね。

    ただしoutにも制約があります。渡す側の初期化が不要になる代わりに、渡されたメソッドでの初期化が必須になります。以下のようにAddValueでcに値の代入をしていない場合エラーになります。refでは渡す側で初期化していればAddValueが空でもエラーにはなりません。

    3つめのinの役割は?

    C#にはrefとout以外にinと言うキーワードもあります。これはC# 7.2から追加されましたが、最新環境ではそのまま利用できます。以下がinを利用したC#サンプルです。

    inを使えば読み取り専用にできる

    上のC#サンプルではsumにinを付与してDispValueメソッドに渡し、DispValueではそれを表示しています。inを付与すると渡されたメソッドの先で値を変更できなくなります。例えば以下のようにするとエラーになります。

    inを付与すると読み取り専用になるということです。フィールドの値を渡したメソッド内で変更されたくない時に利用すれば、間違いを防ぐことができますね。

    ref・out・inの違いのまとめ

    ref・out・inについてまとめると以下のようになります。この3つを正しく使い分けることで、間違って値が更新されることが無いようにしましょう。

    ref
    呼び出す側での初期化=必須
    メソッドでの値の代入=してもしなくても良い

    out
    呼び出す側での初期化=禁止
    メソッドでの値の代入=必須

    in
    呼び出す側での初期化=必須
    メソッドでの値の代入=禁止

    ref・in・outの制約

    ref・in・outには制約があります。非同期のasyncのメソッドと、yield returnを使うメソッドにはref・in・outは使えません。理由はその2つのメソッドは呼び出す時点で結果が不定であるからです。例えば以下のC#サンプルはエラーになります。

    yield returnは行き来が発生するため使用不可

    上のC#サンプルのyield returnは通常のreturnと違いそこでメソッドが終わらずに、値を返しながら最後まで進みます。

    呼び出し側とメソッドでの行き来が発生するため、最初の呼び出しで結果が確定しないという理由でref・out・inを使用できません。なお上のC#サンプルの2か所のinを除去すると正しく動作し、以下のような結果になります。

    4
    5
    6

    ref・out・inの効果的な利用法

    ここまで読んできてref・out・inにあまり使い道が無いように感じた人もいるかもしれません。しかしref・out・inは構造体(struct)を使う時に効果を発揮するのです。以下のC#サンプルをご覧ください。

    ref・out・inを使えば構造体の処理で高速化できる

    上のC#サンプルは構造体をinで渡しています。C#ではクラスを渡す場合は参照渡し、構造体を渡す時は値渡しになります。しかしもし構造体のサイズが大きいと、メソッドに値を渡す時に値渡しのため中身全てを渡すことになって、非常にパフォーマンスが低下します。

    しかしref・out・inを使えば構造体の参照渡しができます。渡すのはアドレスだけになるためパフォーマンスが良くなるのです。なお上のサンプルの結果は以下になります。

    あいうえお
    かきくけこ
    さしすせそ

    システム
    エンジニア
    C#のref・out・inのそれぞれの違いや制約についてよく分かりました。
    プロジェクト
    マネージャー
    C#のref・out・inはあるケースでは必須の機能ですので、それぞれの違いをしっかり理解して、活用してください。

    C#のref・out・inを活用しよう

    C#のref・out・inについて活用しましたがご理解頂けましたでしょうか。構造体を利用する時にパフォーマンス改善のために必要になるので、是非活用してください。

    FEnet.NETナビ・.NETコラムは株式会社オープンアップシステムが運営しています。
    株式会社オープンアップシステムロゴ

    株式会社オープンアップシステムはこんな会社です

    秋葉原オフィスには株式会社オープンアップシステムをはじめグループのIT企業が集結!
    数多くのエンジニアが集まります。

    秋葉原オフィスイメージ
    • スマホアプリから業務系システムまで

      スマホアプリから業務系システムまで

      スマホアプリから業務系システムまで開発案件多数。システムエンジニア・プログラマーとしての多彩なキャリアパスがあります。

    • 充実した研修制度

      充実した研修制度

      毎年、IT技術のトレンドや社員の要望に合わせて、カリキュラムを刷新し展開しています。社内講師の丁寧なサポートを受けながら、自分のペースで学ぶことができます。

    • 資格取得を応援

      資格取得を応援

      スキルアップしたい社員を応援するために資格取得一時金制度を設けています。受験料(実費)と合わせて資格レベルに合わせた最大10万円の一時金も支給しています。

    • 東証プライム上場企業グループ

      東証プライム上場企業グループ

      オープンアップシステムは東証プライム上場「株式会社夢真ビーネックスグループ」のグループ企業です。

      安定した経営基盤とグループ間のスムーズな連携でコロナ禍でも安定した雇用を実現させています。

    株式会社オープンアップシステムに興味を持った方へ

    株式会社オープンアップシステムでは、開発系エンジニア・プログラマを募集しています。

    年収をアップしたい!スキルアップしたい!大手の上流案件にチャレンジしたい!
    まずは話だけでも聞いてみたい場合もOK。お気軽にご登録ください。

    株式会社オープンアップシステムへのご応募はこちら↓
    株式会社オープンアップシステムへのご応募はこちら↓

    C#新着案件New Job