const修飾子は、値がコンパイル時に決まっていて、プログラムの実行中に変化しないフィールドになら(そして一般にはそうすべきですが)適用できます。
private const int num = 1729;
public const string title = "Grand" + " Master";
readonly修飾子は、constにはできないフィールドになら適用できます。そうしたフィールドは、プログラムの実行中に値が変化せず、インライン初期化子か、インスタンス化のとき(コンストラクター、またはコンストラクターから呼ばれるメソッド)に値が設定されます。こちらも一般には適用しておくべきです。
private readonly int num;
private readonly System.Random rand = new System.Random();
public MyClass(int num)
{
this.num = num;
}
セキュリティーが重要な場面では(あるいは、開発者の優先順位や思惑がそれぞれ違うような大規模なコードベースでは、それだけでも)、次のような状態は避けるべきです。すなわち、メソッドの可変な引数を受け取って保存したり、クラスの可変なメンバーを戻り値やout引数として公開したりして、クラスのパブリックAPIを迂回できてしまう状態です。
readonly修飾子は、フィールドの値や参照が上書きされるのを防ぎますが、参照型のメンバーは保護しません。
readonly List<int> ints = new List<int>();
void Foo()
{
ints.Add(1); // ok
ints = new List<int>(); // fails to compile
}
参照型のすべてのメンバーを保護するには、フィールドをreadonlyにし、自動プロパティをsetアクセサーなしで定義します。
基底クラスライブラリー(BCL)には、コレクションのメンバーが更新されないようにする必要がある場合のための、読み取り専用バージョンのコレクションが用意されています。それらはラッパーという形で提供されます。
ReadOnlyDictionary<T>は、Dictionary<T>を読み取り専用として公開します。ReadOnlyCollection<T>は、List<T>を読み取り専用として公開します。前回developer-privilegesで見た認証システムに、少し手を入れる必要があります。コードを整理する仕事を任されました。このような整理作業は、将来コードを保守する人にとっての負担を減らすだけでなく、いくつかのセキュリティ上の脆弱性を見つけて修正することにもつながります。
constにするこれはリファクタリングの作業です。AuthenticatorやIdentityのメンバーのうち、適切だと思うものにconst修飾子を付けてください。
readonlyにするこれはリファクタリングの作業です。AuthenticatorクラスやIdentity構造体のフィールドのうち、適切だと思うものにreadonly修飾子を付けてください。
AuthenticatorクラスやIdentity構造体の適切なプロパティからsetアクセサーを削除するか、privateにしてください。
現時点では、管理者のIDフィールドはAdminの呼び出しで返されます。呼び出し元がこのフィールドを変更できてしまうため、好ましくありません。Authenticatorオブジェクト上の管理者の詳細を、呼び出し元が変更できないようにする方法を考えてください。
現時点では、ハードコードされた特権エンジニアの識別情報を格納した辞書は、GetDevelopers()の呼び出しで返されます。呼び出し元がこの辞書を変更できてしまうため、好ましくありません。Authenticatorオブジェクト上のエンジニアの詳細を、呼び出し元が変更できないようにする方法を考えてください。