tonari note

オンラインゲームエンジニアの雑記

【メモ】C#で迷った時の決め事

C#で「どう書こうかな」って迷った時にルール統一させようと思ってメモしておきます。
以下、俺俺文法。

  • List.ForEachかforeachか。

基本的にforeach。
ただし、{}を使わないときはList.ForEachでも良い。

// すべてのキャラのパワーを元に戻す
characters.ForEach(_ => _.Power = _.DefaultPower);

  • 文字列連結は+かConcatか。

いやまぁFormatが便利なんだけども、値型ではカプセル化起きてしまう。
1文で収まる短い連結は+でいい気がするので+。
複数行にわたるような長い連結はConcat。
ただ、ファイルパスの連結とかはPath.Combineとか使うべきなので時と場合。

  • インデクサの使いどころ

シーケンス、IEnumerableなもののみ。

// 選ばれたアイテム
var selected = itemBox[5];

// データテーブルから取得とかはメソッドにしてる
var characterData = CharacterDataTable.SearchData(characterId);

  • プロパティかメソッドか

極力プロパティ。
プロパティはフィールドと同じで連続で取っても変わらないもの。
メソッドは取るタイミングで変わってしまうもの。

// ItemUidの作成
var uid = ItemUid.NewUid();

// ItemUidの取得
var uid = item.Uid;

ただ、System.DateTime.Nowとか例外。

  • メソッド名

当然動詞から始めるけどもいくつか例外認めている。
ただ新規にインスタンス返すときとかPowerShellチックにNewHoge。
違う型に変換する時はToHoge。
データテーブルからIDで取るか名前でとるかとかは単純にオーバーロード、ByとかFrom(?)とか使わない。
TryParseとか積極的に真似ていくスタイル。

// ItemUidの作成
var uid = ItemUid.NewUid();

// これはオーバーロード
var characterData = CharacterDataTable.SearchData(characterId);
var characterData = CharacterDataTable.SearchData(characterName);

// stringから変換はPerse/TryPerse
string source;
CharacterDataTable table;
if (!CharacterDataTable.TryPerse(source, out table))
return;

  • 条件外れるときはできるだけreturnしてネスト浅く

if (!CharacterDataTable.TryPerse(source, out table))
return;

  • ToString()

値型の場合は絶対使えなので、文字列変換するときは全部使えで統一。

  • {get; private set;}かreadonlyか

コンストラクタ内でしか代入しないならreadonlyで極力自動実装プロパティ避ける。
実際、僕は{get; private set; }より{get; internal set;}とか多い。

  • privateプロパティとかpublic変数とか。

public変数はUpperCamel。
privateプロパティは気持ち悪いのでメソッドにしてる。

  • IDかIdか、UIDかUidか

C#的に2文字はUpper-Upperだけども、僕はもう全部Upper-Lowerにしている。

  • structかclassか

structはItemIdとかで使っている。

  1. 16バイト以下
  2. immutable
  3. 各種ジェネリクスインターフェイス実装(IEquatable、IComparable等)
  4. に付随する比較演算子とかもオーバーロード(==とか<とか)
  5. Objectのメソッドはオーバーライド(ToString()とか)
  6. IComparableとかを引数にするメソッドとかはジェネリクス化。
  7. T4テンプレートとかで大量生産。

基本、メモリ密度上げよう+カプセル化は絶対避けようの方針。
この辺面倒だけども、使う側が値か参照かとか決められないのは凄く好き。
(逆にC++とか使う側で決められること多過ぎて非常に非常にクソい。)

  • 同じ機能のLINQを使うか使わないか

同じ機能が提供されている場合は極力LINQの方使わない。

// Count()じゃなくてCount
list.Count;

// ElementAtじゃなくてインデクサ
list[5];

// Containsはstringのほう、'h'にするとLINQの方使われる
"hoge".Contains("h");


他にもあると思うんですが、とりあえず頭に浮かんだ分だけです。
サンプルはあくまでニュアンスなので「コンパイル通らないけど!」とかは無しでお願いします。