概要
個人的にC#のプログラミングで気を付けていることです。一部は言語を問わないと思います。知っていれば、今日から簡単に気をつけることが可能なことを記載しています。
Windows Formsアプリを作成しているので偏っているかもしれません。個人的な好みもあると思いますし、正しいと主張しているわけではないので変なところがある場合にご指摘していただけると助かります。
1. 副作用を少なくする
個人的に一番主張したいことはこれです。
これは想定外の動きを少なくするために心掛けていることです。
自分の組んだプログラムでも2、3ヵ月たてば具体的な中身は忘れてしまいます。後々の苦労を減らすためにも副作用や影響範囲が明示的なプログラムを組むように心がけています。
副作用 (プログラム)
1.1 staticな関数にする
staticな関数にすることにより、メンバー変数が思いがけず書き換えられることがないことを保証できます。極端ではありますがアクセスレベルがprivateでメンバー変数を触る必要のない関数は全部staticにしてしまえと思うぐらいです。
public int AnyProcess()
{
// メンバー変数が変更されるかどうかわからない
}
public static int AnyProcess()
{
// メンバー変数が変更されることはない
}
1.2 IReadOnlyListを使用する
中身が変更されることのないリストです。
IReadOnlyList インターフェイス
引数をIReadOnlyListとして受け取ることで関数内でリストが変更されることないことがわかります。
public List<int> AnyProcess(List<int> list)
{
// 引数のListが変更されるかどうかがわからない
}
public List<int> AnyProcess(IReadOnlyList<int> list)
{
// 引数のListが変更されないことが明示的
}
またプロパティの型をIReadOnlyListにすることにより、プロパティを参照する側は、このリストに対して直接AddしたりRemoveすることが想定されていないことがわかります。
private List<int> m_IntList;
// そのまま返す場合
// 中身の変更が可能なので変更されてもいい場合以外はだめ
public List<int> IntList { get { return m_IntList} }
// Arrayに変換する場合
// 基本的にはこれで問題ないと思う
public int[] IntList { get { return m_IntList.ToArray(); } }
// IReadOnlyListとして公開する
// 変更されたくないのが明示的。クラスの外からは基本的に変更されないはず
// キャストすれば変更可能だけど...そこまでして変更する必要のある場合ともとれる?
public IReadOnlyList<int> IntList { get { return m_IntList; } }
2. 公開範囲は小さくする
これはプログラムの変更をしやすくするための心得です。
後々変更するときに影響範囲を調べる必要が減ります。また変数が変更される範囲がわかりやすくなるので、どこで変更されているか調べる手間が減ります。
2.1 必要最低限のアクセスレベルにする
関数や変数はprivateでいいならprivateで宣言して、internal⇒publicと
必要に応じて広げるようにします。
protectedは特殊ですが、意外と公開範囲は広いので気を付けてください
C#のアクセス修飾子 2019 〜protectedは 結構でかい〜
2.2 private set
プロパティを公開したいことはあると思いますが、外からsetする必要がなければプロパティのsetterはprivate setにします。
// クラスの外から変更可能
public int AnyValue { set; get; }
// クラスの外から変更不可
public int AnyValue { private set; get; }
2.3 readonly宣言とget-only property
コンストラクタ以外で変更する必要のない値はreadonlyをつけることにより、インスタンスが変更されないことが保証されます。(※Listの中身が変更されたり、クラスのメンバが変更されることはある)
また値を公開したい場合等はgetterだけの自動実装プロパティを用いることでコンストラクタ以外で変更されないことが保証できます。
public class GetterSample
{
public double Name{ get; }
public GetterSample(string name)
{
// 変更の必要がない場合get-onlyプロパティ
Name= name;
}
}
自動実装のget-onlyプロパティとpublic readonlyな変数の大きな違いはinterfaceで使用できるかどうかかなと思います。
public interface ISample
{
// プロパティはインターフェースでももてる
string Hoge1 { get; }
// これはだめ。フィールドはもてない
readonly string Hoge2;
}
3. 見やすくする
見やすいってなんだって主観が入ることかもしれませんが、技術的にはそれほど難しくないことだけ。
3.1 適切にコメントをいれる
プログラムにコメントを書こうって話です。コメントの必要ないプログラムが書ければ、その方が良いと思いますが、一朝一夕ではいかないので、上手になるまではコメント書いた方がいいと思います。
コメントを書く基準を自分で決めると忘れにくいです。どういうときに書いたらいいかわからんって場合は、ググって誰かの参考にするか、リーダブルコード読むか、とりあえずコメントを書きまくって、しばらくして読み返していらないなってとこを消していって自分ルールを作っていけばいいと思います。
個人的には下記の2つは特に心がけてコメントするように心がけています。
・普通に考えたらこうするよねって記述ではなく一風変わった記述をしたときになぜそうしたかの理由
・苦労して作って計算等、あとから見ると何をしているのかわからないような処理の説明
3.2 長い処理を(なるべく)書かない
**"長くても100行まで。それ以上は処理を分ける"**というように自分が見やすいルールを決めて書くといいと思います。チームで明確な基準があればいいと思うのですが、担当してる箇所によってはどうしても長くなってしまうようなケースもあると思うので基準がない場合は自分の見やすいようにすればいいと思う。
まとめ
ほかにもDRYとか変数や関数の命名とかいろいろ気を付けることはあると思いますが、簡単にできるようになるのは難しいのでここには記載していません。(特に変数や関数の命名ほんと難しいですよね。)
仕様変更に強く、使いやすい処理を書いて幸福なプログラミングライフを送りたい所存です。