11

refキーワードを広範かつ不必要に使用するコードを継承しました。元の開発者は、 refを使用しない場合、オブジェクトがプリミティブ型のように複製されることを明らかに恐れており、5 万行以上のコードを記述する前に問題を調査しませんでした。

これは、他の悪いコーディング慣行と相まって、表面上はとてつもなく危険な状況を生み出しています。例えば:


Customer person = NextInLine(); 
//person is Alice
person.DataBackend.ChangeAddress(ref person, newAddress);
//person could now be Bob, Eve, or null

住所を変更するために店に足を踏み入れ、まったく別の人として店を出ることを想像できますか?


恐ろしいことですが、実際には、このアプリケーションでのrefの使用は無害に見えます。クリーンアップにかかる膨大な時間を正当化するのに苦労しています。アイデアを売り込むために、次の質問をします。

他にどのように ref を不必要に使用すると破壊的になる可能性がありますか?

特にメンテナンスには力を入れています。例を含むもっともらしい答えが優先されます。

また、クリーンアップは必要ないと主張することもできます。

4

7 に答える 7

8

最大の危険は、パラメーターがnull何らかの理由で関数内に設定されている場合です。

public void MakeNull(ref Customer person)
{
    // random code
    person = null;
    return;
}

今、あなたはただの別人ではなく、完全に存在から抹消されました!

このアプリケーションを開発している人が次のことを理解している限り:

デフォルトでは、オブジェクト参照は値によって渡されます。

と:

キーワードを使用するrefと、オブジェクト参照は参照によって渡されます。

コードが期待どおりに機能し、開発者がその違いを理解している場合、それらをすべて削除するのにかかる労力に見合う価値はおそらくありません。

于 2009-04-14T18:56:18.277 に答える
4

私が今まで見た ref キーワードの最悪の使用法を追加します。メソッドは次のようになりました。

public bool DoAction(ref Exception exception) {...}

そうです、メソッドを呼び出すには、例外参照を宣言して渡す必要がありました。次に、メソッドの戻り値をチェックして、例外がキャッチされ、ref 例外を介して返されたかどうかを確認します。

于 2009-04-14T18:59:14.447 に答える
2

コードの作成者が、パラメーターを参照として持つ必要があると考えた理由を理解できますか? 彼らがそれを更新してから機能を削除したためですか、それとも単に当時 c# を理解していなかったからですか?

クリーンアップする価値があると思われる場合は、特に時間がある場合は、先に進んでください。緊急のバグ修正である可能性が高く、適切な作業を行う時間がないため、実際の問題が発生したときに適切に修正する立場にない可能性があります。

于 2009-04-14T18:59:55.710 に答える
1

C# では、メソッドの引数の値を変更することは非常に一般的です。これは、通常は参照ではなく値によるものであるためです。これは、参照型と値型の両方に適用されます。たとえば、参照を null に設定すると、元の参照が変更されます。これは、他の開発者が「いつものように」作業しているときに、非常に奇妙で痛ましいバグにつながる可能性があります。ref 引数を使用して再帰メソッドを作成することはできません。

これとは別に、ref で渡すことができるものには制限があります。たとえば、定数値、読み取り専用フィールド、プロパティなどを渡すことができないため、ref 引数を使用してメソッドを呼び出すときに多くのヘルパー変数が必要になります。

最後に重要なことを言い忘れましたが、おそらくパフォーマンスはそれほど良くありません。これは、より多くの間接参照が必要であり (ref は、アクセスごとに解決する必要がある単なる参照です)、参照が外部に出ないため、オブジェクトをより長く存続させることもできるためです。迅速にスコープします。

于 2009-04-14T19:00:49.047 に答える
0

他にどのように ref を不必要に使用すると破壊的になる可能性がありますか?

他の回答は、間違いなく最も重要なことであるセマンティックの問題を扱っています。良いコードは自己文書化されており、ref パラメーターを指定すると、それ変更されると想定します。そうでない場合、API は自己文書化に失敗しています。

しかし、楽しみのために、別の側面、つまりパフォーマンスを見てみましょう。

void ChangeAddress(ref Customer person, Address address)
{
    person.Address = address;
}

personこれは参照への参照であるため、アクセスするたびに何らかの間接化が導入されます。これが次のように変換される可能性のあるアセンブリを見てみましょう。

mov eax, [person]           ; load the reference to person.
mov [eax+Address], address  ; assign address to person.Address.

現在、非参照バージョン:

void ChangeAddress(Customer person, Address address)
{
    person.Address = address;
}

ここには間接性がないため、1 つの読み取りを取り除くことができます。

mov [person+Address], address  ; assign address to person.Address.

[person]実際には、.NET がバージョンにキャッシュし、ref複数のアクセスで間接コストを償却することが期待されます。ここにあるような些細な方法以外では、実際には命令数が 50% 減少することはないでしょう。

于 2013-09-04T23:58:05.963 に答える