質問
メソッドから値を取得する場合は、次のようにいずれかの戻り値を使用できます。
public int GetValue();
または:
public void GetValue(out int x);
私はそれらの違いを本当に理解していないので、どちらが良いかわかりません。これを説明してもらえますか?
ありがとう。
解決
out
パラメーターを持つvoidメソッドが ever 必要なケースは考えられません。C#7の Deconstruct
言語でサポートされている分解のメソッドは、このルールの非常にまれな例外として機能します。)
他のことは別として、呼び出し側が変数を個別に宣言する必要を防ぎます:
int foo;
GetValue(out foo);
vs
int foo = GetValue();
Out値は、次のようなメソッドチェーンも防ぎます。
Console.WriteLine(GetValue().ToString("g"));
(実際、これもプロパティセッターの問題の1つであり、ビルダーパターンが myStringBuilder.Append(xxx).Append(yyy)
などのビルダーを返すメソッドを使用する理由です。 )
さらに、出力パラメーターはリフレクションで使用するのが少し難しく、通常はテストも難しくなります。 (通常、出力パラメータよりも戻り値のモックを作成しやすくするためにより多くの労力が費やされます)。基本的に、彼らが簡単 ...
にすることは考えられません。FTWの戻り値。
編集:何が起こっているのか...
基本的に" out"の引数を渡すときパラメータ、変数を渡す があります。 (配列要素も変数として分類されます。)呼び出すメソッドには、「新規」がありません。パラメータのスタック上の変数-変数をストレージに使用します。変数の変更はすぐに表示されます。違いを示す例を次に示します。
using System;
class Test
{
static int value;
static void ShowValue(string description)
{
Console.WriteLine(description + value);
}
static void Main()
{
Console.WriteLine("Return value test...");
value = 5;
value = ReturnValue();
ShowValue("Value after ReturnValue(): ");
value = 5;
Console.WriteLine("Out parameter test...");
OutParameter(out value);
ShowValue("Value after OutParameter(): ");
}
static int ReturnValue()
{
ShowValue("ReturnValue (pre): ");
int tmp = 10;
ShowValue("ReturnValue (post): ");
return tmp;
}
static void OutParameter(out int tmp)
{
ShowValue("OutParameter (pre): ");
tmp = 10;
ShowValue("OutParameter (post): ");
}
}
結果:
Return value test...
ReturnValue (pre): 5
ReturnValue (post): 5
Value after ReturnValue(): 10
Out parameter test...
OutParameter (pre): 5
OutParameter (post): 10
Value after OutParameter(): 10
違いは" post"です。ステップ-ローカル変数またはパラメーターが変更された後。 ReturnValueテストでは、これは静的な value
変数と違いはありません。 OutParameterテストでは、 value
変数は tmp = 10;
他のヒント
より良いのは、特定の状況に依存します。 out が存在する理由の1つは、1つのメソッド呼び出しから複数の値を返すことを容易にするためです:
public int ReturnMultiple(int input, out int output1, out int output2)
{
output1 = input + 1;
output2 = input + 2;
return input;
}
したがって、定義上、一方が他方より優れているわけではありません。ただし、通常は、たとえば上記の状況がない限り、単純なリターンを使用する必要があります。
編集: これは、キーワードが存在する理由の1つを示すサンプルです。上記はベストプラクティスと見なされるべきではありません。
通常は、出力パラメータよりも戻り値を優先する必要があります。 2つのことを行う必要があるコードを記述していることに気付いた場合、out paramsは必需品です。この良い例は、Tryパターン(Int32.TryParseなど)です。
2つのメソッドの呼び出し元が何をしなければならないかを考えてみましょう。最初の例では、これを書くことができます...
int foo = GetValue();
変数を宣言し、メソッドを介して1行で割り当てることができます。 2番目の例では、このように見えます...
int foo;
GetValue(out foo);
変数を事前に宣言し、2行でコードを書くことを余儀なくされました。
更新
これらのタイプの質問をする際に見るのに適した場所は、.NET Framework設計ガイドラインです。書籍版をお持ちの場合は、Anders Hejlsbergなどによるこのテーマに関する注釈(ページ184〜185)を見ることができますが、オンライン版はこちらです...
http://msdn.microsoft.com/en -us / library / ms182131(VS.80).aspx
APIから2つのものを返す必要がある場合は、それらを構造体/クラスにラップする方が、出力パラメーターよりも優れています。
まだ言及されていない out
パラメータを使用する理由が1つあります。呼び出しメソッドはそれを受信する義務があります。メソッドが、呼び出し側が破棄してはならない値を生成する場合、それを out
にすると、呼び出し側は強制的に具体的にそれを受け入れるようになります。
Method1(); // Return values can be discard quite easily, even accidentally
int resultCode;
Method2(out resultCode); // Out params are a little harder to ignore
もちろん、発信者は out
パラメータの value を無視できますが、注意を呼びかけました。
これはまれなニーズです。より頻繁に、真の問題に例外を使用するか、「FYI」の状態情報を含むオブジェクトを返す必要がありますが、これが重要な状況もあります。
主に好みです
返品が好きです。複数の返品がある場合は、結果DTOでラップできます
public class Result{
public Person Person {get;set;}
public int Sum {get;set;}
}
ほとんどの場合、戻り値を使用する必要があります。 「 out
」パラメーターは、多くのAPI、構成性などに多少の摩擦をもたらします。
頭に浮かぶ最も注目すべき例外は、 TryParse
パターンなどのように、複数の値を返す場合(.Net Frameworkには4.0までタプルがありません)です。
戻り値は1つしか持てませんが、複数の出力パラメーターを持つことができます。
これらの場合は、パラメータのみを考慮する必要があります。
ただし、メソッドから複数のパラメーターを返す必要がある場合は、おそらくオブジェクト指向アプローチから何を返すかを調べ、これらのパラメーターを持つオブジェクトまたは構造体を返す方が良いかどうかを検討する必要があります。したがって、再び戻り値に戻ります。
この単純な例のいずれかではなく、以下を好むでしょう。
public int Value
{
get;
private set;
}
しかし、それらはすべて同じです。通常、メソッドから複数の値を渡す必要がある場合にのみ「out」を使用します。メソッドの内外に値を送信する場合は、「ref」を選択します。値を返すだけの場合は私の方法が最適ですが、パラメータを渡して値を取得する場合は、おそらく最初の選択肢を選択します。
それらは両方とも目的が異なり、コンパイラによって同じように扱われません。メソッドが値を返す必要がある場合は、returnを使用する必要があります。メソッドが複数の値を返す必要がある場合は、Outが使用されます。
returnを使用する場合、データは最初にメソッドスタックに書き込まれ、次に呼び出し元のメソッドに書き込まれます。 outの場合、呼び出し元のメソッドスタックに直接書き込まれます。他に違いがあるかどうかはわかりません。
実際の違いはありません。outパラメーターはC#にあり、メソッドが複数の値、つまりすべてを返すことができます。
ただし、若干の違いがありますが、どれも非常に重要ではありません:
outパラメーターを使用すると、次のような2行の使用が強制されます。
int n;
GetValue(n);
戻り値を使用している間、1行で実行できます:
int n = GetValue();
別の違い(値型についてのみ、C#が関数をインライン化しない場合にのみ正しい)は、OUTパラメーターを使用している間に関数が戻るときに必ず戻り値を使用すると値のコピーが作成されることです。
他の人が言っているように:戻り値であり、出力パラメータではありません。
「フレームワーク設計ガイドライン」という本をお勧めします。 (第2版)?ページ184〜185には、パラメータを回避する理由が記載されています。本全体が、あらゆる種類の.NETコーディングの問題について正しい方向に導くでしょう。
Framework Design Guidelinesと連携しているのは、静的解析ツールFxCopの使用です。これは、Microsoftのサイトで無料でダウンロードできます。コンパイルされたコードでこれを実行し、それが何を言っているかを見てください。それが何百ものことについて文句を言うなら...パニックにならないでください!それぞれのケースについて何を言っているかを静かに注意深く見てください。急いで物事を修正しないでください。それがあなたに言っていることから学ぶ。習得への道を歩むことになります。
アンマネージメモリを使用する場合、それが役立ついくつかのシナリオの1つであり、「返された」ということを明確にしたいと思います。値は、それ自体で破棄されることを期待するのではなく、手動で破棄する必要があります。
さらに、戻り値は非同期設計パラダイムと互換性があります。
関数「非同期」を指定することはできません。 refまたはoutパラメーターを使用する場合。
要約すると、戻り値により、メソッドの連鎖、より明確な構文(呼び出し側が追加の変数を宣言する必要性を排除することにより)が可能になり、将来の大幅な変更を必要とせずに非同期設計が可能になります。
boolの戻り値のタイプでoutキーワードを使用すると、コードの肥大化を抑え、読みやすさを向上させることができます。 (主に、出力パラメータの追加情報がしばしば無視される場合。)たとえば:
var result = DoThing();
if (result.Success)
{
result = DoOtherThing()
if (result.Success)
{
result = DoFinalThing()
if (result.Success)
{
success = true;
}
}
}
vs:
var result;
if (DoThing(out result))
{
if (DoOtherThing(out result))
{
if (DoFinalThing(out result))
{
success = true;
}
}
}
outは、メソッドで宣言したオブジェクトを返そうとする場合に便利です。
例
public BookList Find(string key)
{
BookList book; //BookList is a model class
_books.TryGetValue(key, out book) //_books is a concurrent dictionary
//TryGetValue gets an item with matching key and returns it into book.
return book;
}
戻り値は、メソッドによって返される通常の値です。
out パラメーターとして、well outとrefはC#の2つのキーワードであり、変数を参照として渡すことができます。
ref と out の大きな違いは、 ref は前に初期化する必要があり、 out は初期化しないことです。
この質問に目を向けるつもりはありませんが、私は経験豊富なプログラマーである非常にです。
値を返す手続き(VRP)が決定論的で純粋であることがオブジェクト指向プログラミング言語に適していると思います。
'VRP'は、式の一部として呼び出される関数の最新の学名であり、式の評価中に呼び出しを概念的に置き換える戻り値を持ちます。例えば。 x = 1 + f(y)
などのステートメントでは、関数 f
はVRPとして機能します。
「確定的」とは、関数の結果がパラメーターの値のみに依存することを意味します。同じパラメータ値でもう一度呼び出すと、同じ結果が得られます。
'Pure'は副作用がないことを意味します。関数を呼び出しても、結果の計算以外は何も行いません。これは、実際には重要の副作用がないと解釈できるため、たとえばVRPが呼び出されるたびにデバッグメッセージを出力する場合は、おそらく無視できます。
したがって、C#で関数が決定的で純粋でない場合、 void
関数(つまり、VRPではない)にする必要があると言います。 returnは、 out
または ref
パラメータで返される必要があります。
たとえば、データベーステーブルからいくつかの行を削除する関数があり、削除した行の数を返すようにするには、次のように宣言する必要があります。
public void DeleteBasketItems(BasketItemCategory category、out int count);
時々この関数を呼び出したいが count
を取得したくない場合は、常にオーバーロードを宣言できます。
このスタイルがオブジェクト指向プログラミングにより適しているなぜを知りたいかもしれません。概して、(少し不正確に)「手続き型プログラミング」と呼ばれるプログラミングスタイルに適合し、オブジェクト指向プログラミングにより適した手続き型プログラミングスタイルです。
なぜですか?オブジェクトの古典的なモデルは、オブジェクトには属性(別名属性)があり、それらのプロパティを読み取り、更新することにより、オブジェクトを(主に)問い合わせて操作します。手続き型のプログラミングスタイルでは、プロパティの取得と設定を行う操作の間に任意のコードを実行できるため、これが簡単になります。
手続き型プログラミングの欠点は、どこでも任意のコードを実行できるため、グローバル変数と副作用を介して非常に鈍く、脆弱な相互作用を取得できることです。
したがって、非常に簡単に言えば、コードを読んでいる人に、関数が値を返さないことによって副作用が発生する可能性があることを合図することをお勧めします。