web-dev-qa-db-ja.com

「in」パラメータ修飾子はコードのにおいと見なされますか?

C#7.2 + 以降、パラメータータイプの前にパラメーター修飾子inを追加して、パラメーターを本質的にconstとして定義できます。

これはrefまたはoutキーワードに似ていますが、呼び出されたメソッドではin引数を変更できない点が異なります。 - [〜#〜] msdn [〜#〜]

MSDNの例:

void InArgExample(in int number)
{
    number = 19; // error CS8331, it prevents modification of this parameter
}

なぜそれが役立つのですか?渡された引数がその関数を呼び出した結果として変更されないことを呼び出し元に保証できます。言い換えれば、約束。


SOLID設計原則とロバートマーティンによるクリーンコードによると、これはoutパラメータと同じ行に沿ったコード臭いと見なされますか?

出典:

今週のコードのにおい:Outパラメータに夢中

出力パラメーターの何が問題になっていますか?

7
Reap

あなたはMSDNから一線を引いてしまいました。

ページの最も重要な部分は最初の文です: "inキーワードは引数を参照渡しします。"それはこの点で主に、キーワードはoutおよびrefに似ています。

これは、大きなstructsを関数に渡すときに重要です。キーワードなしで渡すと、構造体がコピーされるため、非効率的です。 (変更は外部に表示されるべきではありません。)参照渡しはより効率的です。

ただし、この目的で古いoutおよびrefキーワードを使用すると、問題が発生します。 outはまったく役に立ちません。関数に情報を渡すために使用することはできません。 refは可能ですが、混乱を招きます。これにより、関数はパラメーターを変更できます(変更は外部に表示されます)。これは構造体では珍しいことです。これを行うと、バグの原因となる可能性があります。そして、意図しないのであれば、それは間違った意図を伝えています。

したがって、inキーワード:構造体を変更せずに参照で構造体を渡す方法。したがって、あなたが引用した文。

ちなみにinを使用して、パラメーターを変更しないようにして(MSDNの例のように)、効率を向上させるのではなくisコードの臭いをします。 intsをinとして渡さないでください。いずれにせよ、変更は関数の外で見ることができないので、通常の値渡しパラメーターの変更を防ぐ意味はありません。 (これは一部の新しいプログラマーを混乱させますが、値渡しと参照渡しを理解することはとにかく学ぶ必要があるものです。)

16
Sebastian Redl

いいえ、キーワードinを使用して、参照によって渡される引数を読み取り専用のメソッドにすることは、コードのにおいではありません。

入力パラメーターの変更は副作用です。それは、推論が難しく、変更が難しいコードに簡単につながる可能性があります。

Bertrand Meyerのコマンドクエリ分離原則(CQS)では、メソッドはコマンドまたはクエリのいずれかである必要があると規定されています。メソッドがコマンドの場合、(インスタンス変数の)状態は変化しますが、何も返しません(void)。メソッドがクエリの場合、戻り値はありますが状態は変化しません。

この原則に従うと、コードは通常、理由付けが容易になり、バグが少なくなります。たとえば、値を返すメソッドは何回でも安全に呼び出すことができ、常に同じ結果を生成します。

inキーワードに戻ります。 MSDNによると:

これらの引数を参照渡しすることで、(潜在的に)高価なコピーを回避できます

Inキーワードを使用すると、引数が参照としてメソッドに渡されることを呼び出し元に通知しますが、変更されないため安全です。

補足として、メソッドシグネチャでinを使用する場合は、呼び出し元でも指定することをお勧めします。これは意図を示しており、inのないオーバーロードがある場合、そのメソッドが最初に選択されます。

4
Rik D

「イン」と「アウト」という言葉は互いに関連していますが、この場合はかなり違うと思います。 outキーワードは出力を返す別の方法を提供しますが、inパラメータは入力パラメータに「読み取り専用」を追加する方法に似ています。これが発信者にとって重要であるかどうかにかかわらず、私は本当に決めることができません。とにかくネーミングからは明らかだと思います。

1
Noceo