2015-12-30 14 views
16

この名前付き引数のルールとは何ですか?

void RegisterUser(string firstname, string lastname, int age); 

誰かがfirstnamelastname引数をミックスすることが簡単ですので、私はそれらを呼び出すときに私は明示的にこのようなメソッドの引数に名前を付けるなどのような方法を考えてみましょう。ただし、ageでは実際には必要ありません。例えば、私はこれが明快さの観点からはOKであると思うでしょう。

RegisterUser(firstname: "John", lastname: "Smith", 25); 

しかし、次のエラーがスローされます:

名前付き引数の仕様は、すべての固定引数がもう一つの興味深いものがある

指定された後に表示される必要があり、その署名は

だったら
void RegisterUser(int age, string firstname, string lastname); 

これをfoll owsはエラーを発生しません

RegisterUser(25, firstname: "John", lastname: "Smith"); 

なぜC#はこのように設計されていますか?最初のシナリオが許可されていれば、コンパイラに問題はありますか?

+0

私は、Pythonでさえこのデザインを強制することは確信しています。私は、もしPythonが何かを強制するならば、それはおそらく非常に必要であるという経験則です。議論の順序は非常に必要です。 – James

+0

@Jamesはい、pythonは順序付けを強制しますが、C#では、引数を明示的に命名した後に引数を並べる必要はありません。しかし、引数の部分的な名前付けが行われたときに順序付けを行うと、コードを自己文書化しやすくなり、コードを理解しやすくなります。 –

+0

両方の言語で明示的に引数の名前を付けることができます。おそらく、私はそのことを以前より貧弱に言いました。同じ関数呼び出しで順序付けられた引数から明示的な命名に移動できますが、元に戻ることはできません。両方の言語で同じです。 – James

答えて

14

コンパイラはそれを理解することができますが、人間にとっては、25が第1または第3のパラメータを参照するかどうかを知ることはほとんど不可能です。特に、引数を混在させる可能性を開くからです。なぜそうでないのですか

MyFunction(firstname: "josh", 25, "smith", someotherargument: 42) 

あなたはこれを年齢と姓のために25と解釈しますか?そのためのルールを作って、コンパイラが実装することができます。しかし、人間には何が意味をなさないでしょうか。以前の引数が、後に命名されている場合は奇妙なことは、順序で起こって開始:コードの難読化は

簡単な言語を簡単に

NOTE、それはハードエラーをしないようにすべきであるということではありません。 (私の例ではファーストネーム&のように)、名前のない引数を正しい引数にマップするためのパズルになるためです。コードはパズルを生成しません。

+0

を許可しないようにする理由を知りません。いくつかの議論の名前を付けることであろうが、他には難しいコードを書くのが容易ではないだろうか?私が書いたコードでは、 'age'引数に名前を付ける必要がほとんどありません。なぜそれを拒否するのですか?特に、部分的な名前付けに引数が揃う必要がある場合は特にですか? –

+0

これは私の質問の編集としては適切かどうかはわかりませんが、なぜ以下のルールは適切ではないでしょうか。名前のない引数が名前付き引数の後に来る場合、コンパイラはどの引数がどちらであるかを解決するためにのみ順序を使用します。 "これにより、あいまいさがなくなり、いくつかの名前付き引数に名前が付けられていない場合よりも、コードを読みにくくすることはありません。 –

6

これは、引数に名前を付けると、コンパイラは名前に基づいてそれをマップし、必要なすべての引数が存在する限り関数定義を無視するからです。あなたの場合、それは何が25であるかを知らない。その後、

void RegisterUser(string firstname, string lastname, int age = 0, int weight = 0); 

と言う:

RegisterUser(firstname: "John", lastname: "Smith", 25); 

はその後、コンパイラはそれをどうするかを知らない私たちにそれが年齢である必要がありますが、あなたはあなたの例を変更した場合は、その論理思われます関数を呼び出すこの方法は、ほとんどの場合、いくつかの値を設定したいだけの多くのデフォルト値を持つ関数で使用されます。

引数を指定しないときは、基本的に関数定義で設定された構造に厳密に従うと言っています。

+0

ああ、これは理にかなっています。規則は、コンパイラが名前付き引数を参照するとすぐに変更されます。名前付き引数が見つかる前に、順序を決めてください。後:注文はもはや重要ではありません。引数のいくつかだけが命名され、名前のない引数が続いた場合、引数が順番でなければならないというルールがあった場合、どうなりますか? –

+0

これは混乱し、コードの読みやすさを低下させます。もし私がこのようなことをしたら、どうすればいいのですか? RegisterUser(firstname: "John"、 "Smith"、25); 「スミス」とは何ですか?ファーストネーム? –

+0

私には、少なくともRegisterUser( "John"、 "Smith"、25)と同じくらい明確です。しかし、どこから来ているのか分かります。 –

1

名前付き引数はすべて、定位置引数の後に付ける必要があります。スタイルを切り替えることはできません。位置引数は、常にメソッド宣言の対応するパラメータを参照します。定位置引数を後で名前付き引数で指定することで、パラメータをスキップすることはできません。コンパイラは、一時的なローカル変数を使用します。その後、引数スロット内のそれらの地域を並べ替えると、コンパイラは名前付き引数が見つかるまで引数によってバインドされ、名前なしですでにバインドされている引数は破棄され、コンパイラは一時的なローカル変数を使用して並べ替えられます。バインド名前で残りは、例えば、それは年齢その後、並べ替えファーストネームと25をバインド:「ジョン」、姓:「スミス」

1

と意図される使用:例として

void M(int a = -1, int b = -1, int c = -1, int d = -1, int e = -1); 

、ということですあなたは、これらのオプションのパラメータのいずれかの位置表記法によってサブセットを指定することができます。

M(42, 28, 101); // gives a, b, and c in order; omits d and e 

か、名前付き引数を使用することができます。

M(d: 50, a: 42, c: 101); // gives three arguments in arbitrary order 
あなたは位置引数で始まり、その後、引数に名前を付けるに切り替え

またはあなたがそれらを組み合わせることができ、:

M(c: 101, 7, 9, b: 28, 666); // ILLEGAL! 

でしょう:

M(42, 28, e: 65537, d: 50); // mixed notation OK 

あなたが遭遇した制限の理由は、のようなその原料であります混乱する。

わかりやすくするために、特定の呼び出しで位置的な順序を保持し、いくつかの引数の名前だけを含めることをお勧めします。しかし、この使用法は言語設計者の優先事項ではなかったようです。

すべての名前付きスタイルを使用する理由がわかりやすい場合(パラメータの適切なサブセットのみを指定する必要はない)、名前を付けることをお勧めします。

+1

あなたの答えをありがとう。 "この使用は言語デザイナーの優先事項ではないようです。"私は賢明だと思います。これは機能として追加されたのは実際の理由ではないと私は考えなかったため、これを使用したかったのですが。 –

0

この場合の言語設計は、どの関数の最初の名前付き引数を使用していると思いますか?

あなたの例

void RegisterUser(int age, string firstname, string lastname); 

を使用すると、コンパイラは、この関数はまったく名前付き引数を使用しようとしているかどうかを知らない最初の引数に遭遇する前に

RegisterUser(25, firstname: "John", lastname: "Smith"); 

それを呼び出します。したがって、コンパイラがシーケンシャルマッピングを行うことは安全な前提です。

25:

は、コンパイラは、最初の引数を取得し、それは、それがすぐに関数定義から最初の引数にマップされます非名付けものであれば。

ファーストネーム:

コンパイラは、現在名前付き引数をマッピングするための関数定義で言及したすべての残りの引数をチェックする必要がありますやいなや、それが最初の引数の名前だ遭遇すると、物事が変更されます。

それが最初の名前付き引数をうまくマッピングした後、順次マッピングのトレイルが壊れています。したがって、コンパイラに名前の付いていない引数を提供することは現時点では不可能です。

名前のない最後の引数を覚えておいてそこからシーケンシャルマッピングを開始する必要があると思うならば、定義された名前付き引数が順番に正しいかもしれないのでエラーが発生しやすくなります。

姓:

そして、それが風だ名前付き引数のために。

希望します。

1

位置指定引数は名前付き引数の前に置かれます。 位置引数は、常にメソッド宣言の対応するパラメータを参照します。

私の方法があるとします

void Dimensions(int height, int breadth , int length); 

と私はこの場合、

Dimensions(3, length: 12, 24); 

のようにそれを呼んでいる:

3 '' は、第1のパラメータであるとを指し、 '24'は3番目のパラメータで、lengthを参照していますが、すでにlengthの値を指定しています。

は、そのため、おそらくデフォルトのC#のスタイルによって、この障害を克服するために、正しい参照を提供するために、開始時に位置引数を配置することです。

また、省略可能なパラメータを定義している場合は、最後に位置パラメータを指定すると誤った結果につながる可能性があります。

+0

正しい答えと思われる –

+0

私のためにかなりうまく動く –

関連する問題