web-dev-qa-db-ja.com

静的クラスでのconstの使用

私は オープンソースプロジェクト 先週末に遭遇したときにプラグインしていました 私を混乱させたコードのビットC#仕様)の使用法を調べるために

問題のコードは次のとおりです。

internal static class SomeStaticClass
{
    private const int CommonlyUsedValue = 42;

    internal static string UseCommonlyUsedValue(...)
    {
        // some code
        value = CommonlyUsedValue + ...;

        return value.ToString();
    }
}

これは静的関数によって使用されている非静的フィールドであるように思われるため、私は不意を突かれました。これは、静的クラスでうまくコンパイルされています。

仕様は次のように述べています(§10.4):

定数宣言には、属性のセット(§17)、新しい修飾子(§10.3.4)、および4つのアクセス修飾子の有効な組み合わせ(§10.3.5)を含めることができます。属性と修飾子は、constant-declarationによって宣言されたすべてのメンバーに適用されます。 定数は静的メンバーと見なされますが、定数宣言では静的修飾子は必要ありません。同じ修飾子が複数回表示されるのはエラーです。定数宣言で。

定数は静的メンバーと見なされるため、今ではもう少し意味がありますが、文の残りの部分は私には少し驚きです。 定数宣言が静的修飾子を必要とせず、許可しないのはなぜですか?確かに、私はこれが最初にすぐに意味をなすのに十分な仕様をよく知りませんでしたが、定数が静的であると見なされた場合に静的修飾子を使用しないように決定されたのはなぜですか?

その段落の最後の文を見ると、それが前のステートメントに直接関係していて、最初に定数に暗黙の静的修飾子があるのか​​、それとも定数の別のルールとしてそれ自体が立っているのかがわかりません。誰かが私がこれを片付けるのを手伝ってくれる?

31
Nick Larsen

基本的に、constは、実行時に値を変更できないため、staticをすでに意味します。 static constはすでに暗示されているため、宣言する理由はありません。言語設計者は、言語構文にそれを反映させることにしました。

仕様言語は基本的に「Constは常に静的であるため、冗長であるため、staticとconstを明示的に言うことはできません」と言っています。

43
Reed Copsey

更新: この質問は2010年6月10日の私のブログの主題でした。 すばらしい質問をありがとう!

定数が静的であると見なされる場合、定数に静的修飾子の使用を強制しないという決定がなされたのはなぜですか?

定数が静的であると見なされると仮定します。 3つの可能な選択肢があります:

  1. 静的にするoptional: "const int x ..."または "static const int x ..."はどちらも有効です。

  2. 静的にする必須:「constint x ...」は無効、「static const intx ...」は有効です

  3. 静的にするillegal: "const int x ..."は有効であり、 "static const int x ..."は無効です。

あなたの質問は、なぜ私たちが(3)を選んだのですか?

1999年のデザインノートには書かれていません。確認したところです。しかし、おそらく言語設計者の頭を通り抜けていたものを推測することはできます。

(1)の問題は、「const intx ...」と「staticconstint y ...」の両方を使用するコードを読み取ることができ、自然に「違いは何ですか?」と自問することです。非定数フィールドとメソッドのデフォルトは「静的」でない限り「インスタンス」であるため、自然な結論は、一部の定数はインスタンスごとであり、一部はタイプごとであり、その結論は間違っているということです。誤解を招くため、これは悪いことです。

(2)の問題は、最初に冗長であるということです。言語に明快さや​​表現力を加えることなく、タイピングを増やすだけです。そして第二に、私はあなたのことを知りませんが、コンパイラが私に「ここで魔法の言葉を言うのを忘れました。あなたが魔法の言葉を言うのを忘れたのを知っています、私は100パーセント能力があります」というエラーを私に与えるとき、私は個人的にそれを嫌います魔法の言葉がそこに行く必要があることを理解するのですが、あなたが魔法の言葉を言うまで、私はあなたにどんな仕事もさせないつもりです。」.

(3)の問題は、constが論理的に静的を意味することを開発者が知る必要があることです。ただし、開発者がこの事実を知ると、彼らはそれを学びました。これは、理解するのが難しい複雑なアイデアではありません。

エンドユーザーに最も少ない問題とコストを提示する解決策は(3)です。

これを、さまざまな決定がなされた言語の他の場所と比較対照するのは興味深いことです。

たとえば、オーバーロードされた演算子は、パブリックと静的の両方である必要があります。この場合も、次の3つのオプションに直面します。

  1. public staticをオプションにし、

  2. 必要にする、または

  3. それを違法にします。

オーバーロードされた演算子には、(2)を選択しました。メソッドの自然な状態はプライベート/インスタンスであるため、(1)と(3)の両方が必要とするように、メソッドのように見えるものを目に見えない形でパブリック/静的にすることは奇妙で誤解を招くように思われます。

別の例では、基本クラスの仮想メソッドと同じ署名を持つ仮想メソッドには、「新規」または「オーバーライド」のいずれかが含まれている必要があります。繰り返しますが、3つの選択肢があります。

  1. オプションにします。newと言うか、オーバーライドするか、何も言わないでください。この場合、デフォルトでnewになります。

  2. 必須にする:新規と言うかオーバーライドするか、または

  3. 違法にする:新しいとはまったく言えないので、オーバーライドと言わないと、自動的に新しいものになります。

この場合、(1)を選択しました。これは、誰かの脆弱な基本クラスの状況に最適であるため、現在オーバーライドしていることに気付かない基本クラスに仮想メソッドを追加します。これにより警告が生成されますが、エラーは生成されません。

私のポイントは、これらの状況のそれぞれをケースバイケースで検討する必要があるということです。ここには一般的なガイダンスはあまりありません。

60
Eric Lippert

冗長であるため、必須または許可されていません。すべてのconstメンバーが静的である場合、somestaticとして指定し、一部を指定しないことで混乱が生じる可能性があります。

9
Adam Robinson

定数を静的として宣言することを許可しないもう1つの理由は、CLRの観点から、定数がそのタイプの他の静的フィールドと一緒にメモリに格納されないことです。

定数にはメモリアドレスがなく、定数値への参照を取得できません(唯一の例外は文字列定数です)。実行時に、他の静的/非静的メンバーが参照されていない場合、定数定義を保持する型はロードされません。アセンブリ内の唯一のタイプである場合は、コンパイル後にディスクからDLL)を安全に削除することもできます。

したがって、定数は「静的メソッド」から参照できるという点でのみ「静的」です。定数には、他の静的型メンバーのように他の「静的」プロパティはありません。

0
Artemix