27

constなぜ C# がクラスまたはメソッド レベルでサポートしないのか、しばらく疑問に思っていました。Jon Skeet が長い間不変性のサポートを望んでいたことは知っています。関数 const の C++ 構文を使用すると、そのサポートが得られると考えています。クラス レベルで const キーワードを追加することで、完全なサポートが得られます。

さて、私の質問は、C# チームがこの種のサポートを開発しなかった理由は何ですか?

CLRを変更する必要なく、コンパイル時のチェックまたは属性を使用してすべてを作成できると思います。コードがリフレクションを通じて const の動作をオーバーライドできることは気にしません。

これを想像してください:

const class NumberContainer
{
    public int Number { get; }
}

.. このようなクラスは、構築時にしか設定できないため、int を受け取るコンストラクターが必要になります。

もう 1 つの例は、メソッド レベルの const です。

public int AddNumbers(NumberContainer n1, NumberContainer n2) const
{
   return n1.Number + n2.Number;
}

const レベルのメソッドは、自身のクラスまたは渡された参照型のインスタンスの状態を変更できないようにする必要があります。また、const レベルの関数は、そのスコープ内にある間だけ、他の const レベルの関数を呼び出すことができました。

ラムダとデリゲートがすべてを達成するのを困難にする (または不可能にする) かどうかはよくわかりませんが、言語とコンパイラの設計の経験が豊富な人が教えてくれると確信しています。

Steve B がコメントで指摘したように、 の存在により、 const との間はほぼ同じになるためreadonly、物事が少し複雑になりますが、コンパイル時に値を決定することはできません。とレベリングを行うこともできると思いますが、それではややこしすぎるのではないでしょうか?readonlyruntimereadonlyconstreadonly

では、これを実装しない理由は何ですか?使いやすさの問題 (C++ の const を理解することは、通常、新規ユーザーには非常に困難です)、言語設計の問題 (実行できません)、または単純に優先順位の問題 (不変性に関する話題の時代は終わりました) ..?

4

6 に答える 6

26

やや循環的な説明を危険にさらすと、CLR は const をまったくサポートしていないため、C# は const をサポートしていません。CLR は、CLS に完全に準拠していないため、サポートしていません。

この概念を持つ言語はほとんどありません。C 言語は const をサポートしています。これは、C# でreadonlyキーワードによって十分にサポートされています。しかし、大きな犬はもちろん、 const の適用範囲がはるかに広い C++ です。間違いなく、あなたが探しているものです。const が何を意味するのかを特定するのは避けます。それ自体がワームホールであり、const を適用するプロパティである「const-ness」についてだけ話します。

const-ness の問題は、それを強制する必要があることです。これは、任意の他の言語が C# クラスを使用でき、言語がそれをサポートしていないという理由だけで const-ness を完全に無視できる場合、C# の問題です。C# がサポートしているという理由だけで他のすべての CLS 言語に追加することは、もちろん非常に非現実的です。

強制可能性は C++ でも問題です。この言語は const_cast<> もサポートしているためです。どのクライアント コードも const-ness を迅速かつ診断不能にキャストできます。するべきではありませんが、そうしなければならない場合もあります。const-ness には、strict と observable の 2 種類があるためです。private const-ness と public const-ness にほぼ類似しています。mutableキーワードは、監視可能な const-ness の必要性に対処するために後で言語に追加されたため、少なくとも const_cast<> の必然的な使用を回避できました。C++ は難しい言語だと言う人もいます。C# のそれはあまり聞きません。

于 2012-04-11T08:36:23.567 に答える
3

CLR を変更する必要はないと言いますが、コンパイルされたアセンブリ内でこの "const" 性を表現する標準的な方法はなく、これらのアセンブリは C# コードによって消費されない可能性があると考えてください。これは、C#だけでできることではなく、すべての .NET 言語で行う必要があります。

于 2012-04-11T07:41:02.933 に答える
2

私はかつて次のような状況に驚いていました。

class Vector
{
    private double[] m_data;
    public int Dimension {get;set;}

    public double this[int i]
    {
        get {return m_data[i];}
        set {m_data[i] = value;}
    }

    public Vector(int n)
    {
        this.Dimension = n;
        this.m_data = new double(n);
    }

    public static Vector Zero(int n)
    {
        Vector v = new Vector(n);
        for (int i = 0; i < n; i++)
        {
            v[i] = 0.0;
        }

        return v;
     }

    public static readonly Vector Zero3 = Zero(3);
}

Vector.Zero3は読み取り専用であり、割り当てることはできません。コンポーネントにアクセスすることはできますが、次のような愚かなことが起こります。

Vector a = Vector.Zero3;
a[0]     = 2.87;

そして今、それVector.Vector3への参照に他ならないので、後者にもVector.Vector3 [0] == 2.87があります!

一度この穴に落ちた後、私は非常に単純なハックを発明しましたが、エレガントではありませんが、その機能を果たしています。

つまり、静的な読み取り専用の「定数」を生成すると思われるクラスに、ブールフラグを導入します。

class Vector
{
    private double[] m_data;
    public int Dimension {get;set;}
    private bool m_bIsConstant = false;
    ...

    public double this[int i]
    {
        get {return m_data[i];}
        set 
        {
           if (!m_bIsConstant)
           {
                m_data[i] = value;
           }
        }
    }
    ...
    public static Vector Zero(int n)
    {
        Vector v = new Vector(n);
        for (int i = 0; i < n; i++)
        {
            v[i] = 0.0;
        }

        v.m_bIsConstant = true;
        return v;
     }
     ...
}

このハックは、静的読み取り専用変数が変更されないことを保証します。

于 2012-11-29T14:56:23.593 に答える
2

私がそうであると信じているように、constC++ と比較して C# では異なることを意味します。

C# では、キーワードを使用して、readonly必要な機能のレベルを取得できますconst

于 2012-04-11T07:41:05.663 に答える
1

const クラスの提案の場合、次のように言います。

このようなクラスは構築時にしか設定できないため、int を受け取るコンストラクターが必要になります。

しかし、とにかくすべてのプロパティを読み取り専用にすることで、あなたが言ったことをすでに達成しています。

私は C# 言語の設計者を代弁することはできませんがconst、他の多くの構成要素に適用しなかった理由は、それを追加するだけの価値がなく、他の方法で問題を回避できるためです (上記および他の回答/コメント)。

于 2012-04-11T07:58:38.780 に答える
1

あなたの質問からは、このconstキーワードのオーバーロードが特に有益であるとは言えません。

最初の例は、合法的に次のように書き直すことができます

public class NumberContainer
{
    private readonly int number;

    public NumberContainer(int number)
    {
        this.number = number;
    }

    public int Number
    {
        get { return number; }
    }
}

おそらく、コンパイラがこのクラスの不変性を識別できない場合 (私にはわかりません)、何らかの属性が役立つ可能性がありますか?

2番目の例では、あなたが何を運転しているのかわかりません。関数が定数値を返す場合、定数フィールドに置き換えることができます。

于 2012-04-11T08:00:09.343 に答える