継承関係にあるクラスを作るとき、1 ファイルにたくさんの派生クラスを書くか 1 クラス 1 ファイルで分割するかで悩んだ経験ありませんか?今回はそんな迷える子羊のための機能を紹介します。
1 つのファイルに実装を収める
基本は 1 クラス 1 ファイルのルールを適用するのですが、以下のような理由からあえてルールを守らないケースがあります。
- 関連の近いものは近くに書いておきたい
- 1 ファイルに収めることでソリューションエクスプローラーの肥大化を防ぐ
例えば以下のような感じです。
//--- 以下が全部 DbOperation.cs に書かれているとする public class DbOperation { public virtual int BulkInsert<T>(IEnumerable<T> data) { throw new NotImplementedException(); } } public class SqlServerOperation : DbOperation { public override int BulkInsert<T>(IEnumerable<T> data) { /* 省略 */ } } public class OracleOperation : DbOperation { public override int BulkInsert<T>(IEnumerable<T> data) { /* 省略 */ } } public class MySqlOperation : DbOperation { public override int BulkInsert<T>(IEnumerable<T> data) { /* 省略 */ } } //... 以下省略 ...
とは言え、ひとつのファイルが肥大化するのも結構に困りものです。派生クラス同士を左右に並べて表示するのが辛かったり、パッと目的のクラスに到達するのがやりづらくなります。こうなってくると、やはり 1 クラス 1 ファイルは偉大だと再認識します。
1 クラス 1 ファイルの管理
先のクラスを丁寧にファイル分割してみましょう。以下のようになります。
この例ではまだプロジェクトに含まれるファイルが少ないのでそれほど気になりませんが、継承関係にあるクラスが入っているファイルが名前の並び順の関係で分散し、どこにあるか非常にわかりにくくなってしまいます。
また、個人的にはソリューションエクスプローラーの肥大化を防ぐのは結構重要だと思っています。「Ctrl + :
でファイル検索すればいいじゃん!」というのは当然正しいと思うのですが、なんだかんだ上下スクロールで目的のファイルを探してしまうものです。それなのにファイルが大量になって視認性が悪くなるのは非常に良くない。
「やっぱり 1 ファイルに収めた方が楽なんじゃないか?」という気持ちになってきます。
DependentUpon による入れ子管理
「あちらを立てればこちらが立たず」とはまさにこのことだ!と苦しい思いをするわけですが、どちらの願いをも叶える救世主がいます。それが今回ご紹介する DependentUpon。プロジェクトファイルを少しいじるだけで以下のようなネスト構造を実現できます!
WinForms だと Form.cs
/ Form.designer.cs
、ASP.NET だと Web.config
/ Web.Debug.config
/ Web.Release.config
で見かけるアレですね。こうすることでファイル分割と関連のあるファイルのグループ化を達成できます。最近私が作っている DeclarativeSql でも取り入れました。
設定の仕方
やり方はとても簡単で、プロジェクトファイル (.csproj) をテキストエディタで開いて、対象のファイルに DependentUpon タグを追加するだけです。DependentUpon タグの中には親にするファイルを入れてください。
<ItemGroup> <Compile Include="SQLiteOperation.cs"> <!-- 親にするファイルを指定して追加 --> <DependentUpon>DbOperation.cs</DependentUpon> </Compile> <Compile Include="PostgreSqlOperation.cs"> <DependentUpon>DbOperation.cs</DependentUpon> </Compile> <Compile Include="MySqlOperation.cs"> <DependentUpon>DbOperation.cs</DependentUpon> </Compile> <Compile Include="UnmanagedOracleOperation.cs"> <DependentUpon>DbOperation.cs</DependentUpon> </Compile> <Compile Include="OracleOperation.cs"> <DependentUpon>DbOperation.cs</DependentUpon> </Compile> <Compile Include="SqlServerCeOperation.cs"> <DependentUpon>DbOperation.cs</DependentUpon> </Compile> <Compile Include="SqlServerOperation.cs"> <DependentUpon>DbOperation.cs</DependentUpon> </Compile> <Compile Include="IDbConnectionExtensions.cs" /> <Compile Include="IDbTransactionExtensions.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="DbOperation.cs" /> </ItemGroup>
編集が終わったらプロジェクトファイル (.csproj) を再読み込みさせてください。
File Nesting 拡張機能でお手軽設定
ここまでで目的は十分達成されたのですが、設定には結構メンドクサイものがあります。
- テキストエディタで手書きする
- プロジェクトファイルの再読み込みが必要
そこで File Nesting という Visual Studio 拡張を使いましょう。これがあれば GUI で設定ができます!超お手軽ですね!