2015-09-07 6 views
7

おそらくこれは私の素朴なものですが、私は実際には「参考文献」のためのまともなユースケースを見つけたり、考えることができません。不変の文字列を変更することは一般的に避けられ、複数の変数を返すことは一般的にタプル、リスト、配列などを返すことで処理されます。参照渡しは単なる遺産ですか?

example on MSDNはひどいです。私はただと宣言するのではなく、Squareメソッドの値を返すだけです。

それは、それが不可欠な部分ではなく、C#の遺産部分のように思えます。私よりもスマートな人が、なぜそれがまだ周辺にあるのか、実際には実際に使用されているのかを説明しようとすることができますか(ほとんどの場合、不変の文字列を変更することは避けられます)。

+0

1つではなく2つ以上の(値型)変数の値を調整する必要がある関数を定義した場合はどうなりますか? – Adimeus

+0

この例は実際にはっきりとしています。 'ref'がどのように動作し、どのように使用するのかを正確に示しています。しかし、私は正直なところ、他のものよりも 'ref 'を使う状況を考えることができないので、私はいくつかの答えも見たいと思います。 –

+4

呼び出された関数を使って2つの変数を更新したいのですが?この場合、refは2つの変数をrefとマークすることで役立ちます。 – DarkKnight

答えて

6

P.S:私は@KallDrexx@newacctによって、コメントの一部にまで続きます。私は今、彼らが正しいと分かりました。私は間違っていました。私の答えはやや誤解を招いていました。優れたarticle "Java is pass-by-value, dammit!" by Scott Stanchfield(Javaに特化していますが、依然としてC#とほとんど関係しています)がついに私を納得させました。

私の回答の誤解を招くようなビットは、今のところ まで打ち切りましたが、後で削除する可能性があります。参照によって


パスがただ ref又は outパラメータで使用されていません。さらに重要なのは、すべての参照型は参照によって渡されます(したがって、その名前)。これは透過的に起こります。大 struct Sの

  • 防止コピー周り渡す:ここ

    は、参照渡しのための3つの 頻繁 ユースケースです。大量のフィールドを含むstruct型の値の値の可能性も数メガバイトを表す byte[]のバイナリラージオブジェクト(BLOB)を表す配列があるとします。そのタイプの値は、潜在的にかなりのメモリを占有する可能性があります。これで、この値をいくつかのメソッドに渡したいとします。あなたは本当に価値のあるもの、つまり一時的なコピーを作成したいのですか?

    大きな構造体の不要なコピーを避けるには、refによってそれらを渡します。

    (配列の内容がすでにrefenceで渡されるので、幸いにも私たちのために、このよう byte[]として配列は、参照型です。)

    ことが多い(例えばMicrosoft's Framework Design Guidelinesに)提案されているタイプは、付加価値を持っています型セマンティクスは、特定のサイズ(32バイト)を超える場合は参照型として実装する必要があります。したがって、このユースケースはあまり頻繁ではありません。

  • 変異性。メソッドが渡されるstructの値を突然変異させたい場合、呼び出し元にそのオブジェクトのバージョンの突然変異を観察させたい場合は、参照渡し(ref)が必要です。値が値によってメソッドに渡されると、コピーを受け取ります。コピーを変更すると元のオブジェクトは変更されません。

    この点は、上記にリンクされているFramework Design Guidelineの記事にも記載されています。

    変更可能な値の型(例えば、"Why are mutable structs evil?"を参照してください)に対して広く推奨されています。 refまたはoutのパラメータと値の型を使用する必要はほとんどありません。 this answerで述べたように

  • COM相互運用機能は、多くの場合、refoutパラメータを宣言する必要があります。

+0

BLOBの処理は意味があります。私が遭遇したことではないので、私はそれを考えなかった。ありがとう! – Trent

+0

@FizzBu​​zz:しかし、確かにあなたは、ある時点で、あるいは長さが数文字以上のメソッドに文字列を渡しました。それが値渡しされた場合は、常に文字バッファ全体をコピーする必要があります。幸いにも、 'string'と' char [] 'の両方が参照型なので、それは起こりません。しかし、場面の背後にある参照渡しはまだあります。 – stakx

+0

ええ、私は参照型は少し特別なシナリオだと思います。それはC#のシーンの背後にあります。私はinteropの例のように 'ref 'を指定する必要があるときにもっと興味があります。 – Trent

4

はあなたが値(お知らせ、、ないオブジェクト)を変異させる機能を持っているしたいとします。また、その機能は、いくつかの成功の指標を返すようにしたいです。良い方法は成功/失敗を示すブール値を返すことですが、値はどうですか?だから、あなたが使用ref

bool Mutate(ref int val) 
{ 
    if(val > 0) 
    { 
    val = val * 2; 
    return true; 
    } 
    return false; 
} 
+0

この場合、 'try'メソッドを使ってコードの残りの部分と一緒に' out'パラメータを使用しませんか? (もちろん、あなたはこの方法で使うことができます。) – Sayse

+1

@Sayse - なぜそれが良いのか分かりません。不必要な例外を追加し、混乱するAPIを生成します。 'ref'は明白で、有効な値を期待し、' out'は初期化されていない変数を受け入れることができます。 – Amit

+0

コードの残りの部分がおそらくそれを使用しているので( 'int.TryParse'など)、私は一貫性を優先します。私はあなたの答えに同意していません – Sayse

3

それは、C#でrefoutへの通常の選択肢があることは事実だ - たとえば、あなたが呼び出し側に複数の値を返すようにしたい場合は、あなたが、タプルを返すことができますか、カスタム型を使用したり、パラメータとして参照型を受け取り、内部で複数の値を変更することができます。

しかし、これらのキーワードはまだ相互運用のような状況で便利なソリューションになります

// C 
int DoSomething(int input, int *output); 

// C# 
[DllImport(...)] 
static extern int DoSomething(int input, ref int output); 
+0

'ref'と' out'は物事が参照渡しされる唯一のシナリオではありません。まず、すべての参照型は参照によって渡されます(つまり、参照型は、参照型とも呼ばれます)。 – stakx

+0

@stakx:参照型は**参照**を渡します** value **。*渡された変数のエイリアスではないので、呼び出し側が気づかずにパラメータに新しい値を自由に割り当てることができます。 – Joey

+0

@stakx:実際には、 'ref'キーワードなしで参照型を渡すと、参照渡しではなく、参照渡しとなります。 –

0

明示的なrefパラメータが機能的な観点から有用であるケースはごくわずかです。私が見てきた

一例:

public static void Swap<T>(ref T a, ref T b) 
{ 
    var temp = a; 
    a = b; 
    b = temp; 
} 

このような方法は、例えば、いくつかの並べ替えアルゴリズムに有用です。

refパラメータが使用されることがある理由の1つが最適化手法です。構造体の内容のコピーを避けるために、呼び出されたメソッドが構造体の値を変更する意図がなくても、大きな構造体(値型)がrefによって渡されることがあります。大きな構造体はクラス(つまり参照型)である方がよいと主張することができますが、そのようなオブジェクトの大規模な配列を保持すると(グラフィックス処理など)、欠点があります。最適化されているため、コードの可読性は向上しませんが、状況によってはパフォーマンスが向上します。

ポインタについても同様の質問があります。 C#はunsafefixedのキーワードを使用してポインタをサポートしています。機能的な観点からはほとんど必要とされていません。私は、ポインタを使わなければコード化できなかった機能については本当に考えることができません。しかし、ポインターは、表現力豊かな言語やコードを読みやすくするために使用されるものではなく、低レベルの最適化手法として使用されます。

実際、参照によって構造体を渡すことは、大きな構造体の一般的な低レベルの最適化手法である構造体のデータへのポインタを渡す安全な方法です。

レガシー機能を低レベルで最適化できる機能はありますか?それはあなたの視点に依存するかもしれませんが、唯一のC#ユーザーではありません。彼らの多くは、ポインタやその他の低レベルの構造体が利用できることは、C#が他の言語よりも大きなメリットの1つであることを伝えます。私はrefパラメータがレガシーなフィーチャであるとは考えていませんが、それらは言語の不可欠な部分であり、いくつかのシナリオでは便利です。

には、LINQ、async/awaitなどの言語機能を使用する必要がないのと同じように、にrefパラメータを使用する必要はありません。あなたがそれを必要とするときには、それがそこにあることを喜んでください。