390

この質問にはすでに答えがあります。

違いは何ですかrefそしてout.NETでパラメータ?一方がもう一方よりも役立つ可能性がある状況は何ですか? 1つを使用でき、もう1つを使用できないコードスニペットは何でしょうか。

18 답변


479

それらはほとんど同じです - 唯一の違いはあなたが変数として渡す変数です。outパラメータは初期化する必要はありませんが、refパラメータそれは何かに設定する必要があります。

int x;
Foo(out x); // OK

int y;
Foo(ref y); // Error: y should be initialized before calling the method

Refパラメータは変更される可能性のあるデータ用です。outパラメータは関数の追加出力であるデータ用です(例:int.TryParse)すでに返り値を使っています。


  • また、outパラメータは、呼び出し先に戻る前に呼び出し先の実行中に設定する必要があります。これは、呼び出し先を呼び出す前に呼び出し元によって設定される必要があるrefとは対照的です。 - Jesse C. Slicer
  • @マイクあなたの訂正は間違っています。それは正しかったです。でるparameterに設定する必要があります。を受け取るメソッドoutパラメータは初期化する必要があります。を受け取るメソッドrefパラメータはそれが望むことをすることができます。それはきっとそれを無視することができます。ロールバックしています。 - xanatos
  • 確かに主な違いは、refはデータの入出力にしか使用できないのに対して、refの入力と出力は異なることです。 void works(ref int z)を検討してください。{Debug.WriteLine(z);} notWorks(out int z){Debug.WriteLine(z);}それとも初期化される前にoutパラメータの値を取得するためのトリックが足りないのですか?たとえばデバッガがそれを実行できることに気付きました。 - user159335
  • そのため、途中で何かを設定する必要があるパラメータには、refを使用する必要があります。そうでなければ、使い切る。 - FistOfFury
  • 逆に、refは関数呼び出し中に作成されないようにStructの余分なコピーを保存できます。不利な点として、Classはnullに初期化される可能性があるので、それを防ぐ必要があります。 - Michael Brown

124

なぜC#に 'ref'と 'out'の両方があるのですか?

outパラメータを受け取るメソッドの呼び出し元は、呼び出しの前にoutパラメータとして渡された変数に割り当てる必要はありません。ただし、呼び出し先は戻る前にoutパラメーターに割り当てる必要があります。

対照的に、refパラメータは呼び出し元によって最初に割り当てられたと見なされます。そのため、呼び出し先は使用前にrefパラメータに割り当てる必要はありません。参照パラメータは、メソッドの内外に渡されます。

そう、outを意味しますref出入り用です。

これらは密接に対応します[out]そして[in,out]COMインターフェイスのパラメータ、out呼び出し側のメソッドが不要な場合は、呼び出し側が事前割り当て済みオブジェクトを渡す必要がないというパラメータです。これにより、割り当てのコストと、マーシャリングに関連する可能性があるコストの両方が回避されます。 .NETでは一般的ではありません。


  • 「これとは対照的に、refパラメータは最初に呼び出し先によって割り当てられたものと見なされます」。もちろん、「呼び出し元」を意味しています。私はあなたの答えを編集しようとしました、しかしそれは私にそのような小さな変更を保存させませんでした。 - fpsColton
  • リンクは違いの非常に明確な説明を持っています、ここでほとんどの答えより良いです。ありがとうございます。 - Hannish

82

refそしてout両方とも呼び出されたメソッドがパラメータを変更することを可能にします。それらの違いは何が起こるかですあなたは電話をかけます。

  • refパラメータに値があることを意味します機能に入る。呼び出された関数はいつでも値を読み込んだり変更したりできます。パラメータが入ってから出てくる

  • out関数に入る前にパラメータは公式の値を持たないことを意味します。呼び出された関数はそれを初期化しなければなりません。パラメータは消えるだけです

これを見るための私のお気に入りの方法は次のとおりです。ref参照によって変数を渡すことです。outセカンダリを宣言することです戻り値機能のため。あなたがこれを書くことができるかのようです:

// This is not C#
public (bool, string) GetWebThing(string name, ref Buffer paramBuffer);

// This is C#
public bool GetWebThing(string name, ref Buffer paramBuffer, out string actualUrl);

これが各選択肢の効果のより詳細なリストです。

メソッドを呼び出す前に:

ref:呼び出し側は、呼び出されたメソッドに渡す前にパラメータの値を設定しなければなりません。

out呼び出し元のメソッドは、メソッドを呼び出す前に引数の値を設定する必要はありません。たぶん、そうすべきではありません。実際、現在の値はすべて破棄されます。

通話中:

ref:呼び出されたメソッドはいつでも引数を読み取ることができます。

out:呼び出されたメソッドはパラメータを読み込む前に初期化する必要があります。

リモート呼び出し:

ref:現在の値がリモートコールに整列化されます。追加のパフォーマンスコスト

out:リモートコールには何も渡されません。もっと早く。

技術的に言えば、いつでも使用できますref代わりにoutしかし、out引数の意味についてより正確になることを可能にし、時にはそれがはるかに効率的になることがあります。


15

OUTの例:変数は、メソッドに入ると値が初期化されます。後で同じ値がmainメソッドに返されます。

namespace outreftry
{
    class outref
    {
        static void Main(string[] args)
        {
            yyy a = new yyy(); ;

            // u can try giving int i=100 but is useless as that value is not passed into
            // the method. Only variable goes into the method and gets changed its
            // value and comes out. 
            int i; 

            a.abc(out i);

            System.Console.WriteLine(i);
        }
    }
    class yyy
    {

        public void abc(out int i)
        {

            i = 10;

        }

    }
}

出力:

10年

=================================================

Refの例:変数はメソッドに入る前に初期化されるべきです。後で同じ値または変更された値がmainメソッドに返されます。

namespace outreftry
{
    class outref
    {
        static void Main(string[] args)
        {
            yyy a = new yyy(); ;

            int i = 0;

            a.abc(ref i);

            System.Console.WriteLine(i);
        }
    }
    class yyy
    {

        public void abc(ref int i)
        {
            System.Console.WriteLine(i);
            i = 10;

        }

    }
}

出力:

    0
    10

================================

今はっきりしていることを願っています。


9

  • Aref変数は渡す前に初期化する必要があります。
  • out変数はあなたの関数実装で設定される必要があります
  • outパラメーターは追加の戻り変数(入力ではない)と見なすことができます。
  • refパラメータは入力変数と出力変数の両方として考えることができます。


9

参照および出力パラメータ:

outそしてそのrefパラメータは、メソッドの引数として渡すのと同じ変数に値を返すために使用されます。メソッドが複数の値を返す必要がある場合、これら両方のパラメータは非常に便利です。

caleeメソッド本体のoutパラメータに値を代入する必要があります。そうしないと、メソッドはコンパイルされません。


参照パラメータ:メソッドに渡す前に初期化する必要があります。   のrefメソッドパラメータのkeywordは、同じメソッドの入力パラメータとして渡されたものと同じ変数をメソッドが参照するようにします。変数に何らかの変更を加えると、それらは変数に反映されます。

int sampleData = 0; 
sampleMethod(ref sampleData);

RefパラメータのEx

public static void Main() 
{ 
 int i = 3; // Variable need to be initialized 
 sampleMethod(ref i );  
}

public static void sampleMethod(ref int sampleData) 
{ 
 sampleData++; 
} 

出力パラメータ:Methodに渡す前に初期化する必要はありません。   のoutparameterは、メソッドのパラメータとして渡されたのと同じ変数内の値を返すために使用できます。パラメータに加えられた変更はすべて変数に反映されます。

 int sampleData; 
 sampleMethod(out sampleData);

OutパラメータのEx

public static void Main() 
{ 
 int i, j; // Variable need not be initialized 
 sampleMethod(out i, out j); 
} 
public static int sampleMethod(out int sampleData1, out int sampleData2) 
{ 
 sampleData1 = 10; 
 sampleData2 = 20; 
 return 0; 
} 


6

でる:

C#では、メソッドは1つの値しか返すことができません。複数の値を返したい場合は、outキーワードを使用できます。 out修飾子は参照による戻り値として返します。最も単純な答えは、メソッドから値を取得するためにキーワード「out」が使用されることです。

  • 呼び出し元の関数で値を初期化する必要はありません。
  • 呼び出された関数に値を代入しなければ、コンパイラはエラーを報告します。

参照:

C#では、int、float、doubleなどの値型をメソッドパラメータの引数として渡すと、値によって渡されます。したがって、パラメータ値を変更しても、メソッド呼び出しの引数には影響しません。しかし、もしあなたが“ ref”キーワードでパラメータをマークすると、それは実際の変数に反映されます。

  • 関数を呼び出す前に変数を初期化する必要があります。
  • メソッドのrefパラメータに値を代入することは必須ではありません。値を変更しない場合は、「ref」とマークする必要がありますか。


4

refパラメータは関数内で設定する必要はありませんが、outパラメータは関数を終了する前に値にバインドする必要があります。 outとして渡された変数は、初期化されずに関数に渡されることもあります。


4

outパラメータが出力パラメータであること、つまりメソッドによって明示的に設定されるまで値がないことを指定します。

ref値が値を持ち、その値をメソッド内で変更できる参照であることを指定します。


1

outパラメータは、呼び出されたメソッドによって初期化されます。refメソッドを呼び出す前にパラメータが初期化されます。したがって、out二次戻り値を取得するだけの場合は、パラメータが使用されます。refパラメータは値を取得するために使用されますそして潜在的にその値への変更を返します(2番目に主な戻り値へ)。


1

refキーワードは、参照によって値を渡すために使用されます。 (これは、渡された値が値型または参照型であることを排除するものではありません)。 outキーワードで指定された出力パラメータは、メソッドから値を返すためのものです。

コードの大きな違いの1つは、メソッド内で出力パラメータの値を設定する必要があるということです。これは、refパラメータには当てはまりません。

詳細については見てくださいhttp://www.blackwasp.co.uk/CSharpMethodParameters.aspx


1

outパラメータはref特別なパラメータOut()属性が追加されました。 C#メソッドへのパラメータが次のように宣言されている場合outコンパイラは、パラメータが読み取られる前、およびメソッドが戻る前に、パラメータを書き込むことを要求します。 C#がパラメータを含むメソッドを呼び出す場合Out()attributeを指定した場合、コンパイラは、 "未定義の変数"エラーを報告するかどうかを決定するために、メソッドを呼び出す直前に変数が書き込まれるように見せかけるでしょう。他の.net言語が同じ意味を添付していないので注意してください。Out()属性を使ってルーチンを呼び出すことは可能です。outパラメータは問題の変数に影響を与えません。変数が変数として使用されている場合out確実に代入される前にC#コンパイラが使用される前のある時点で確実にクリアされるようにC#コンパイラはコードを生成しますが、そのような変数がスコープを離れて再び入ると、再度クリアされる保証はありません。


0

refはおそらく既存のオブジェクトを修正することを期待しているので、refはおそらくnullをチョークするでしょう。新しいオブジェクトを返すのでoutはnullを期待します。


  • Foo(ref null)はコンパイルできませんでしたが、文字列bar = null;です。 Foo(ref bar);結構です。 - James Curran
  • null定数をチョーク? James Curranとしては、ref引数で定数を渡すことはできません。 - Andrei Rînea
  • null定数を意味しませんでした。null値を持つ変数を意味しました。 - Joel Coehoorn

0

outとrefは、out変数を深淵に送信する前に初期化する必要がないことを除いて、まったく同じです。私はそんなに賢くはありません、私はそれをMSDNのライブラリから切り取った:)。

しかし、それらの使用についてより明確にするために、修飾子の意味は、あなたがコードの中でその変数の参照を変更した場合、outとrefはあなたの呼び出し側の変数も参照を変更するということです。以下のコードでは、ceSt変数は、doStuffの呼び出しから戻った後のnewGuyへの参照になります。それがref(またはout)用でなければ、参照は変更されません。

private void newEmployee()
{
    Person ceo = Person.FindCEO();
    doStuff(ref ceo);
}

private void doStuff(ref Person employee)
{
    Person newGuy = new Person();
    employee = newGuy;
}


0

このC#のoutとrefのパラメータいくつかの良い例があります。

概説した基本的な違いは、outパラメータは渡されるときに初期化する必要はありませんが、refパラメータは初期化する必要があります。


0

あるとき出力パラメータがメソッド宣言で宣言されている場合、メソッド本体は戻る前にout変数に値を割り当てる必要があります。それで、それが戻る前にoutパラメータに値を代入するのは呼び出されたメソッドの責任です。

あるとき参照パラメータメソッド内で宣言されている場合、メソッドの呼び出し中に渡される引数に値が割り当てられているはずです。そのため、メソッドを呼び出す前にref引数に値を代入するのは呼び出し側の責任です。


0

微妙に違います。

outparameterは、メソッドに渡される前に呼び出し先によって初期化される必要はありません。したがって、outパラメータ

  • 値を割り当てる前にパラメータを読み取ることはできません
  • 戻る前に値を割り当てる必要があります

これは、前の値に関係なく引数を上書きする必要があるメソッドに使用されます。


Arefparameterはメソッドに渡す前に呼び出し先によって初期化されなければなりません。したがって、refパラメータ

  • 割り当てる前に値を調べることができます
  • そのまま、元の値を返すことができます

これは、(例えば)その値を調べてそれを検証するかまたは正規化しなければならない方法に使用される。


0

outはC#7でさらに簡潔な構文を得ましたhttps://docs.microsoft.com/en-us/dotnet/articles/csharp/whats-new/csharp-7#more-expression-bodied-membersさらにもっと刺激的なのは、C#7タプルの機能強化です。これは、refを使用してIMHOを使用するよりも優雅な選択です。

リンクされた質問


関連する質問

最近の質問