ちょっとレアな プログラミング Tips

少し珍しめの Tips をご紹介しますので、よろしければ開発にお役立てください。
★ お探しの情報がここにない場合は【プログラミング相談 ~調べてもわからないときは~】の利用をご検討ください。
★ 解決の難しい問題をお抱えの方は【.NET問題解決 ~難題歓迎/解決保証 諦めてしまう前に~】にてご相談ください。
[+]すべて展開   [-]すべて縮小
DateTime date = DateTime.Today;

▼前月初日
new DateTime(date.Year, date.Month, 1).AddMonths(-1)

▼前月同日
date.AddMonths(-1)

▼前月末日
new DateTime(date.Year, date.Month, 1).AddDays(-1)

▼前々月末日
new DateTime(date.Year, date.Month, 1).AddMonths(-1).AddDays(-1)


▼当月初日
new DateTime(date.Year, date.Month, 1)

▼当月末日
new DateTime(date.Year, date.Month, DateTime.DaysInMonth(date.Year, date.Month))


▼翌月初日
new DateTime(date.Year, date.Month, 1).AddMonths(1)

▼翌月末日
new DateTime(date.Year, date.Month, 1).AddMonths(2).AddDays(-1)


▼1年前の前月初日
new DateTime(date.Year, date.Month, 1).AddYears(-1).AddMonths(-1)

▼1年前の前月末日
new DateTime(date.Year, date.Month, 1).AddYears(-1).AddDays(-1)

▼1年前の当月初日
new DateTime(date.Year, date.Month, 1).AddYears(-1)


▼年度(4月~3月)
date.AddMonths(-3).Year
※以下、Assert.IsTrue なら () 内が 真、Assert.IsFalse なら () 内が 偽です。
※★印の箇所が少し注意が必要な点です。
object o1 = 1;
object o2 = 1;

// ★ボクシング(値型 → object)すると参照比較になります。
// DataRowの各列値(インデクサ/Itemプロパティ)も object 型なので、比較の際は注意しましょう。
Assert.IsFalse( o1 == o2 );

// Object.Equals が int の Equals を呼び出すので値で比較されます。
Assert.IsTrue ( o1.Equals(o2) );
Assert.IsTrue ( Object.Equals(o1, o2) );

int i = 1;
long l = 1;

// 比較演算子
Assert.IsTrue ( i == l );
Assert.IsTrue ( l == i );

// 暗黙の型変換ができるなら Equals で比較できます。
Assert.IsTrue( l.Equals(i) );

// ★暗黙の型変換ができないと Equals で比較できません。
// (コンパイルは通り、例外も発生しないので見逃してしまいがちです。)
Assert.IsFalse( i.Equals(l) );

// ★異なる型へのボックス化解除はできません。
object iBoxed = i;
try {
	// int 型からボックス化されたものを long 型に戻すことはできません。(InvalidCastException が発生)
	bool b = (l == (long)iBoxed);
	Assert.Fail();
}
catch( InvalidCastException ) {}

// ★(おまけ)実行されるのは Object.Equals です。字面だけ見ると true を期待してしまいそう(?)です。
Assert.IsFalse( Type.Equals(1, 2) );

※値型(struct/Structure)の Equals メソッドは、既定ではリフレクションを使用して全フィールド(メンバ変数)をその型の Equals メソッドで比較します。
 値型を自分で作成する場合、Equals メソッドをオーバーライドすることで、この比較処理をカスタマイズすることができます。
 等価演算子(==)を使用するためには、「==」「!=」のオーバーロードを定義する必要があります。
 値型を定義する場合には、Equals メソッドのオーバーライドと等価演算子のオーバーロードが推奨されています。
 ⇒ コード分析(FxCop)CA1815: equals および operator equals を値型でオーバーライドします
Color 構造体の等価判定には少しクセがあります。
Assert.IsTrue( Color.Red == Color.FromName("Red") );
Assert.IsTrue( Color.Red == Color.FromKnownColor(KnownColor.Red) );
ここまでは期待どおりです。
Color redFromArgb = Color.FromArgb(Color.Red.A, Color.Red.R, Color.Red.G, Color.Red.B);
Assert.IsFalse( Color.Red == redFromArgb );
Assert.IsFalse( Color.Red.Equals(redFromArgb) );
ARGBをあわせたのに等価と判定されません。
なぜでしょう。
プロパティを見てみましょう。
Assert.AreEqual( "Red", Color.Red.Name );
Assert.AreEqual( "ffff0000", redFromArgb.Name );

Assert.IsTrue( Color.Red.IsKnownColor );
Assert.IsFalse( redFromArgb.IsKnownColor );

Assert.IsTrue( Color.Red.IsNamedColor );
Assert.IsFalse( redFromArgb.IsNamedColor );
違いが表れました。
これらのプロパティ値は実際の色がどうであるかではなく、Color インスタンスがどのようにして生成されたかによって変わります。
内部的には state という private フィールドに区分が格納され、オーバーライドされた Equals メソッドで比較に使用されます。

実際に表示される色が同じですので、ARGB値で比較すると等価と判定されます。
Assert.IsTrue( Color.Red.ToArgb() == redFromArgb.ToArgb() );

次に浮動小数点型を見てみましょう。

double 型には非数を表す NaN という値があります。
Assert.IsTrue( double.IsNaN(double.NaN) );
double zero = 0d;
Assert.IsTrue( double.IsNaN(0 / zero) );
非数は数ではありませんので、関係演算の結果は false になります。
Assert.IsFalse( double.NaN == double.NaN );
Assert.IsFalse( double.NaN < 0 );
Assert.IsFalse( double.NaN >= 0 );
上の結果を前提にすると、以下は間違えやすいので注意が必要です。
Assert.IsTrue( double.NaN != double.NaN );
Assert.IsTrue( double.NaN.Equals(double.NaN) );
float 型にも NaN があり、double.NaN と値は同じですが、
通常の値の場合と同様、暗黙の型変換ができないと Equals が false を返します。
Assert.IsFalse( double.NaN == float.NaN );
Assert.IsTrue( double.NaN.Equals(float.NaN) );
Assert.IsFalse( float.NaN.Equals(double.NaN) ); // float ← double は暗黙の型変換不可

浮動小数点型では精度も問題になります。
double precision15 = .333333333333333;
double precision17 = 1.0/3;
書式 "R" をつけて最大 17 桁まで確認してみると、有効桁数が異なることがわかりました。
Assert.AreEqual( "0.333333333333333", precision15.ToString("R") );
Assert.AreEqual( "0.33333333333333331", precision17.ToString("R") );
有効桁数が異なるため、等価にはなりません。
Assert.IsFalse( precision15 == precision17 );
Assert.IsFalse( precision15.Equals(precision17) );
有効桁数を Math.Round で揃えると等価と判定されます。
Assert.IsTrue( Math.Round(precision15, 15) == Math.Round(precision17, 15) );
Assert.IsTrue( Math.Round(precision15, 15).Equals(Math.Round(precision17, 15)) );

最後は列挙型です。
メンバとして定義していない値が格納された場合の等価判定について、
テストコード中のコメントで解説させていただきます。
// 列挙型定義
private enum FromOne
{
	One = 1,
	Two
}

// フィールド
private FromOne fromOne;

// 検証
public void EnumDoesNotHaveZeroValue()
{
	// 0 は定義されていません。
	Assert.IsFalse( Enum.IsDefined(typeof(FromOne), 0) );

	// フィールドの既定値は default(T) と一致します。
	Assert.IsTrue( fromOne == default(FromOne) );

	// どのメンバとも一致しません。
	foreach( FromOne each in Enum.GetValues(typeof(FromOne)) ) {
		Assert.IsTrue( fromOne != each );
	}

	// int 値は 0 です。
	Assert.IsTrue( (int)fromOne == 0 );

	// 0 をキャストすると一致します。
	Assert.IsTrue( fromOne == (FromOne)0 );

	// リテラルや定数の場合、キャストしなくでも int 型と比較できます。
	Assert.IsTrue( fromOne == 0 );
	Assert.IsTrue( 0 == fromOne );
	
	/* int 型変数との比較はコンパイルエラーになります。
	int zero = 0;
	Assert.IsTrue(fromOne == zero);
	Assert.IsTrue(zero == fromOne);
	*/

	// int 型との Equals 比較は false になります。
	Assert.IsFalse( fromOne.Equals(0) );
	Assert.IsFalse( 0.Equals(fromOne) );

	// 最大値を超える値
	FromOne maxValue = (FromOne)int.MaxValue;
	Assert.IsTrue( (FromOne)int.MaxValue == maxValue );
}
※FlagsAttribute 属性が付与されていない列挙型では、値ゼロのメンバを定義することが推奨されています。
 ⇒ コード分析(FxCop)CA1008: Enums は 0 値を含んでいなければなりません
参照型の等価比較には、参照の比較と値の比較の2種類があります。
参照の比較には、等価演算子「==」(VB.NET では Is 演算子)、値の比較には Equals メソッドを使用するの基本ですが、
注意が必要な点もいくつかあります。
ここでは、String クラスと StringBuilder クラスを例に、等価判定の動作を検証してみます。
※以下、Assert.IsTrue なら () 内が 真、Assert.IsFalse なら () 内が 偽です。
※★印の箇所が少し注意が必要な点です。

▼String 型 の例
string s1 = new string(new char[]{'a'});
string s2 = new string(new char[]{'a'});
object s1AsObj = s1;
object s2AsObj = s2;

/*【等価演算子】*/
// 等価演算子がオーバーロードされており、値比較となります。
Assert.IsTrue( s1 == s2 );
// ★String 型同士でない場合、等価演算子は参照比較となります。
Assert.IsFalse( s1AsObj == s2AsObj );
Assert.IsFalse( s1 == s2AsObj );
Assert.IsFalse( s2AsObj == s1 );
// 文字列のリテラルは「インターン プール」というテーブルに保持され、同一値に同じ参照が使用されます。
Assert.IsTrue( ReferenceEquals("a", "a") );

/*【Equals メソッド】*/
// Equals メソッドがオーバーロードされているため、値比較となります。
Assert.IsTrue( s1.Equals(s2) );
// Equals(object) メソッドがオーバーライドされているため、値比較となります。
Assert.IsTrue( s1.Equals(s2AsObj) );
// オーバーライドされた Equals メソッドが使用されます。
Assert.IsTrue( s2AsObj.Equals(s1) );

/*【Object.Equals メソッド】*/
// 等価演算子がオーバーロードされているため、true となります。
Assert.IsTrue( Object.Equals(s1, s2) );
// Equals(object) メソッドがオーバーライドされているため、true となります。
Assert.IsTrue( Object.Equals(s1AsObj, s2AsObj) );
/* 《参考》Object.Equals の実装
public static bool Equals(object objA, object objB)
{
    return ((objA == objB) || (((objA != null) && (objB != null)) && objA.Equals(objB)));
}*/

/*【Object.ReferenceEquals メソッド】*/
Assert.IsTrue( Object.ReferenceEquals(s1, s1) );
Assert.IsFalse( Object.ReferenceEquals(s1, s2) );
Assert.IsFalse( Object.ReferenceEquals(s1AsObj, s2AsObj) );
▼StringBuilder 型の例
StringBuilder sb1 = new StringBuilder("a");
StringBuilder sb2 = new StringBuilder("a");
StringBuilder sb1Assigned = sb1;
object sb1AsObj = sb1;
object sb2AsObj = sb2;
string sb1AsStr = sb1.ToString();

/*【等価演算子】*/
// ★等価演算子がオーバーロードされていないため、参照比較となります。
Assert.IsFalse( sb1 == sb2 );
// Object 型の等価演算子では参照比較となります。
Assert.IsFalse( sb1AsObj == sb2AsObj );
/* 「演算子 '==' を 'string' と 'System.Text.StringBuilder' 型のオペランドに適用することはできません。」
 * コンパイルエラーになるため、ToString() の漏れなどミスに気づきます。
Assert.IsFalse( sb1AsStr == sb1 );
*/

/*【Equals メソッド】*/
// Equals メソッドがオーバーロードされているため、値比較となります。
Assert.IsTrue( sb1.Equals(sb2) );
// ★Equals(object) メソッドがオーバーライドされていないため、参照比較となります。
Assert.IsFalse( sb1.Equals(sb2AsObj) );
// ★コンパイルが通るため、ToString を忘れたことなどミスに気づきません。
Assert.IsFalse( sb1AsStr.Equals(sb1) );
Assert.IsTrue( sb1AsStr.Equals(sb1.ToString()) );

/*【Object.Equals メソッド】*/
// ★等価演算子がオーバーロードされていないため、false となります。
Assert.IsFalse( Object.Equals(sb1, sb2) );
// 代入された場合、参照は一致します。
Assert.IsTrue( Object.Equals(sb1, sb1Assigned) );

/*【Object.ReferenceEquals メソッド】*/
Assert.IsTrue( Object.ReferenceEquals(sb1, sb1) );
Assert.IsFalse( Object.ReferenceEquals(sb1, sb2) );
Assert.IsTrue( Object.ReferenceEquals(sb1, sb1Assigned) );
文字列のリテラルは「インターン プール」というテーブルに保持され、同一値に同じ参照が使用されます。
String.Intern メソッドでそれらの参照を取り出すことができます。
string literal = "CodeOne";

// 同一値のリテラルは参照も一致します。
Assert.IsTrue( ReferenceEquals(literal, "CodeOne") );

// 値は同一ですが、参照は異なります。
string built = new StringBuilder().Append("Code").Append("One").ToString();
Assert.IsTrue( Equals(literal, built) );
Assert.IsFalse( ReferenceEquals(literal, built) );

// インターンプールから取得すると、同一値のリテラルと参照が一致します。
Assert.IsTrue( ReferenceEquals(literal, String.Intern(built)) );
※Ngen.exe でアセンブリをコンパイルした場合など、インターンプールに格納されない場合もあります。
《参考》String.Intern メソッド

匿名型では、Equals, GetHashCode メソッドがオーバーライドされています。
// プロパティの数と順序、値が同じ場合
var staffA = new { Id = 1, Name = "山田" };
var staffB = new { Id = 1, Name = "山田" };
// Equals の結果は true になる。
Assert.IsTrue(staffA.Equals(staffB));
Assert.IsTrue(staffA.Equals((object)staffB));
// 参照比較は一致しない。
Assert.IsFalse(staffA == staffB);
Assert.IsFalse(ReferenceEquals(staffA, staffB));

// プロパティの順序が異なる場合
var staffC = new { Name = "山田", Id = 1 };
Assert.IsFalse(staffA.Equals(staffC));

// プロパティの数が異なる場合
var staffD = new { Id = 1, Name = "山田", Role = "開発者" };
Assert.IsFalse(staffA.Equals(staffD));
VB.NET の匿名型では、Key キーワードによって Equals 比較に使用するプロパティを指定できます。
'プロパティの数と順序、値が同じ場合
Dim staffA = New With { Key .Id = 1, Key .Name = "山田" }
Dim staffB = New With { Key .Id = 1, Key .Name = "山田" }
'Equals の結果は true になる。
Assert.IsTrue(staffA.Equals(staffB))
Assert.IsTrue(staffA.Equals(DirectCast(staffB, Object)))
'参照比較は一致しない。
Assert.IsFalse(staffA Is staffB)
Assert.IsFalse(ReferenceEquals(staffA, staffB))

'プロパティの順序が異なる場合
Dim staffC = New With { Key .Name = "山田", Key .Id = 1 }
Assert.IsFalse(staffA.Equals(staffC))

'プロパティの数が異なる場合
Dim staffD = New With { Key .Id = 1, Key .Name = "山田", Key .Role = "開発者" }
Assert.IsFalse(staffA.Equals(staffD))

'Key キーワードがないプロパティは Equals 判定に使用されない。
Dim staffE = New With { Key .Id = 1, .Name = "山田" }
Assert.AreNotEqual(staffA, staffE)

'プロパティの数は Key キーワード以外も一致している必要がある。
Dim staffF = New With { Key .Id = 1, Key .Name = "山田", .Role = "開発者" }
Assert.AreNotEqual(staffA, staffF)

'Key キーワード以外のプロパティは異なっていてもいい。
Dim staffG = New With { Key .Id = 1, Key .Name = "山田", .Role = "開発者" }
Dim staffH = New With { Key .Id = 1, Key .Name = "山田", .Role = "営業担当者" }
Assert.AreEqual(staffG, staffH)
■Windows フォーム

 HawkEye
  実行時にプロパティ、フィールドの確認/変更、イベントハンドラの確認/実行などができます。
  残念ながら .NET 4.0 以降には対応していません。

 wfSpy
  実行時にプロパティの確認/変更ができます。
  .NET 4.0/4.5 でも使用できます。
  ソースコードをダウンロードしてビルドします。
  管理者として実行する必要があります。

■WPF
 
 WPF Inspector
  実行時にXAML 要素をツリー表示し、プロパティやバインドされたビューモデルの中身を確認/変更できます。
  リソース、トリガー、スタイルを確認することもできます。

■Windows ストアアプリ

 Inspect
  Windows 8/8.1 用のソフトウェア開発キット (Windows SDK) に含まれています。
   Windows 8 用 Windows ソフトウェア開発キット (Windows SDK)
    %ProgramFiles(x86)%\Windows Kits\8.0\bin\{architecture}\inspect.exe
   Windows 8.1 用 Windows ソフトウェア開発キット (Windows SDK)
    %ProgramFiles(x86)%\Windows Kits\8.1\bin\{architecture}\inspect.exe

■ASP.NET
 
 Glimpse
  実行時にブラウザ下部に診断結果が表示されます。
  コントロールツリー、サーバーイベント、各フェーズの処理時間、リクエスト、セッション、ルート解析など、
  様々な情報を確認することができます。
  WebフォームでもMVCでも使用できます。
 
 Prefix
  ASP.NET Core に対応しています。
  《セットアップ》
   (1) Prefix をインストールします。
   (2) StackifyMiddleware パッケージを Nuget でインストールします。
   (3) Startup クラスの Configure メソッドで StackifyMiddleware をミドルウェア登録(UseMiddleware)します。
   (4) タスクトレイの Prefix コンテキストメニューから [Enable .NET Profiler] を選択して有効化します。
   (5) タスクバルーンで促されたら Visual Studio を再起動します。
   (6) Webアプリケーションを IIS Express で開始します。
   (7) タスクトレイの Prefix コンテキストメニューから [Open in browser] を選択し、トレースページを開きます。

■ネットワーク
 
 Fiddler
  ブラウザ/非ブラウザの通信をキャプチャしてくれます。
  リクエスト/レスポンスを上下に並べて、テキスト/JSON/XML/クッキーなど様々なビューで確認できます。
.NET の言語仕様の中でも、名前のわかりづらさと概念のややこしさが相まって、
際立ってとっつきづらいのがこの「共変性」「反変性」ではないでしょうか。

もともと .NET 独自の概念ではありませんので、
まずはプログラミング言語における「共変性」「反変性」について整理してみましょう。

1. 前提
 「変性」は、クラス階層(継承関係)における型の互換性に関する概念です。
 派生型のインスタンスは基底型変数に代入して扱うことができますが、これを「代入互換性がある」といいます。
 この互換の方向を維持し、派生型から基底型に変換できることを「共変」といいます。
 方向を反転させ、基底型から派生型に変換できることを「反変」といいます。
 どちらの互換もないときは「不変」です。(.NET の値型では共変性、反変性がサポートされず、「不変」となります。)

2. 簡単な説明
 共変性
  戻り値型について互換性を維持する。(派生型→基底型)
 反変性
  引数型について互換性を反転させる。(基底型→派生型)

3. もう少し詳しく
 共変性がサポートされると...
  「基底型を返す処理(を行う変数)」に「派生型を返す処理(を行うオブジェクト)」を割り当てることができます。
  処理の呼び出し側は基底型が返されることを想定しますが、その中身が派生型であっても不都合はないはずです。
 反変性がサポートされると...
  「派生型を受け取る処理(を行う変数)」に「基底型を受け取る処理(を行うオブジェクト)」を割り当てることができます。
  処理の呼び出し側は派生型を渡しますが、それが基底型として扱われても不都合はないはずです。

4. さらに進んで
 リスコフの置換原則(LSP)との関係
  リスコフの置換原則では、基底型変数の中身を基底型オブジェクトから派生型オブジェクトに置き換えても、
  動作の妥当性が損なわれないことを保証すべきとしています。
  そうすると使う側は、中身の型を(基底型なのか、あるいはどの派生型なのかを)意識しなくてすみますね。
  上記「3. もう少し詳しく」に記載しました(共変性/反変性がサポートされると...)「不都合はないはず」は、
  該当の継承関係においてリスコフの置換原則が守られていることが前提となります。
  リスコフの置換原則に準拠するためのルールには、契約(コントラクト)に関するルールと変性に関するルールがあります。
  [契約に関するルール]
   ・メソッド開始時に成立しているべき事前条件(通常は引数)を派生型で強化することはできない。
   ・メソッド終了時に成立しているべき事後条件(プロパティや戻り値など)を派生型で緩和することはできない。
   ・基底型の不変条件(常に満たされなければならない条件)は派生型でも維持されなければならない。
  [変性に関するルール]
   派生型メソッドの引数型について反変、戻り値型について共変であることを要求します。
   .NET (CLR) ではオーバーライドメソッドで引数型や戻り値型を変えることはできないため、もとより違反することができません。
   (new 修飾子で隠ぺいした場合は基底型変数から new 定義したメンバは呼ばれませんので、ここでは議論の対象外とします。)

いかがでしょう。
おおよその概念はつかんでいただけたでしょうか。

コードを見ないとイメージが湧かない、という方も多くいらっしゃると思いますので、
以下に .NET における「共変性」「反変性」の例をあげていきます。
概念と照らし合わせてご覧ください。

■配列

― 配列の共変性 ―
基底型配列変数に派生型配列を代入できる。
// 参照型 B を参照型 A に代入できるなら、配列 B[] も A[] に代入できる。
string[] strings = new string[] { "a", "b" };
object[] objects = strings;

// 代入後の配列インスタンスは同一参照
Assert.IsTrue( object.ReferenceEquals(objects, strings) );

// ただし、要素に別の派生型の値を設定しようとすると実行時例外が発生する。
try
{
	objects[1] = 1;
	Assert.Fail();
}
catch (ArrayTypeMismatchException ex)
{
	// 「配列と互換性のない型の要素にアクセスしようとしました」
	Console.WriteLine(ex.ToString());
}

// 配列の共変性は、値型には適用されない。
/* 「型 'int[]' を型 'object[]' に暗黙的に変換できません。」
objects = new int[] { 0, 1 };
*/

■デリゲート

― デリゲートの共変性(.NET 2.0 ~) ―
基底型を返すデリゲート変数に派生型を返す処理を代入できる。
public delegate Base BaseGetterDelegate();

public static Base GetBase()
{
	return new Base();
}

public static Derived GetDerived()
{
	return new Derived();
}

static void Test()
{
	BaseGetterDelegate baseGetter1 = GetBase;

	// 共変性がこの代入を可能にする。
	BaseGetterDelegate baseGetter2 = GetDerived;
}
― デリゲートの反変性(.NET 2.0 ~) ―
派生型を受け取るデリゲート変数に基底型を受け取る処理を代入できる。
// EventArgs 型の引数を受け取るイベントハンドラ
private void EventArgsHandler(object sender, EventArgs e)
{
}

public Contravariance()
{
	// KeyDown が期待するイベント引数型は KeyEventArgs だが、EventArgs 型引数のイベントハンドラも登録できる。
	this.KeyDown += this.EventArgsHandler;
}

■ジェネリック

― ジェネリックの共変性(.NET 4 ~) ―
基底型を出力として扱うジェネリック型変数に派生型を出力として扱うジェネリック型オブジェクトを代入できる。
// これは .NET 3.5 でもできた。
IEnumerable<Derived> derivedEnumerable = new List<Derived>();

// 列挙のみなら Base 型で扱っても安全。(互換性のない派生型オブジェクトが要素に追加される心配はない。)
// IEnumerable<out T> のように、戻り値型としてのみ使用される out キーワードで修飾されるようになった。
IEnumerable<Base> baseEnumerable = derivedEnumerable;

// これはできない。(List<Base> には Derived 型以外の派生型も Add できてしまうから)
//List<Base> baseList = new List<Derived>();
//List<Base> baseList = (List<Base>)(new List<Derived>());
― ジェネリックの反変性(.NET 4 ~) ―
派生型を入力として扱うジェネリック型変数に基底型を入力として扱うジェネリック型オブジェクトを代入できる。
Action<Base> baseAction = (target) => { target.DoSomething(); };

// 基底型の引数に派生型のオブジェクトが渡されても問題ない。
// Action<in T> のように、引数型としてのみ使用される in キーワードで修飾されるようになった。
Action<Derived> derivedAction = baseAction;

// 引数を渡す側は、派生型を渡してそれが基底型として扱われても不都合はない。
derivedAction.Invoke(new Derived());

    
.NET では、コンストラクタから仮想メソッドを呼び出すと、
派生クラスのコンストラクタが処理されていない状態でオーバーライドメソッドが呼ばれてしまいます。

例として、基底クラス Base と 派生クラス Derived があるとします。
(括弧内の数字は実行される順番です。)
// 基底クラス
class Base
{
	public Type Initializer { get; protected set; }
	public Base()
	{
		// (2) 基底クラスコンストラクタ処理の実行
		Initialize();
	}
	protected virtual void Initialize()
	{
		Assert.Fail("この仮想メソッドは、コンストラクタから呼び出されません。");
	}
}

// 派生クラス
sealed class Derived : Base
{
	// (1) 派生クラスフィールドの初期化
	private Type type_ = typeof(Base);
	public Derived()
	{
		// (4) 派生クラスコンストラクタ処理の実行
		this.type_ = typeof(Derived);
	}
	// (3) オーバーライドメソッドの実行
	protected override void Initialize()
	{
		this.Initializer = this.type_;
	}
}
実行結果は以下のようになります。
Derived derived = new Derived();
// Initializer プロパティには、Derived コンストラクタでの this.type_ 設定が反映されていません。
Assert.AreEqual(typeof(Base), derived.Initializer);

なお、sealed でない型のコンストラクタからの仮想メソッドを呼び出しは、コード分析(FxCop)で、
「CA2214: コンストラクターのオーバーライド可能なメソッドを呼び出しません。」として警告されます。
単体テストでモックライブラリ「Moq」を利用すると、モックオブジェクトを動的に作成することができて非常に便利です。
ここでは基本的な使い方は割愛させていただき、応用的な使い方をご紹介します。
(アーキテクチャ上/プラクティスとしての是非についてはここでは触れません。)

まずは internal(Friend)メンバのオーバーライド(Setup)からです。
既定では、Moq がオーバーライドできるのは public な仮想メンバのみです。
テスト対象プロジェクトの AssemblyInfo.cs に
[assembly: InternalsVisibleTo("FooTest")]
のような宣言を記述することで、テストメソッドから internal メンバにアクセスすることができますが、
それだけでは十分ではありません(Moq で Setup しても動作をオーバーライドすることはできません)。
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
の宣言を追加すると、Moq で Setup して internal メンバの動作をオーバーライドすることができます。

protected メンバもオーバーライド(Setup)することが可能です。
using ディレクティブで Moq.Protected 名前空間を指定しておくと、

mock.Protected().Setup<bool>("ProtectedMethod", "引数").Returns(true);
のようにして、リフレクションベースではありますが、モック化することができます。

次にご紹介するのは、部分的なオーバーライドの方法です。
モックオブジェクトから呼び出される仮想メンバは、既定で(Setup しなくても)オーバーライドされていますが、
Mock インスタンスの CallBase プロパティに true を設定すると、
明示的に Setup していない仮想メンバについて、基底クラスの動作を保持することができます。
実例を見て見ましょう。
以下のようなテスト対象クラスがあるとします。
public class SampleClass
{
  public virtual bool PublicVirtualProperty {
    get { return true; }
  }
  
  public virtual bool PublicVirtualMethod()
  {
    return true;
  }
  
  public virtual void WriteArg( string arg )
  {
    Console.WriteLine("WriteArg が引数 \"{0}\" で呼ばれました。", arg);
  }
}
既定の Mock インスタンスでテストすると次のようになります。
// モックオブジェクト
Mock<SampleClass> mock = new Mock<SampleClass>();
SampleClass sample = mock.Object;

// プロパティをオーバーライド
mock.SetupGet(s => s.PublicVirtualProperty).Returns(false);

// 検証
Assert.IsFalse(sample.PublicVirtualProperty);
Assert.IsFalse(sample.PublicVirtualMethod()); // ★Setup していないので既定のオーバーライドで false が返る。
mock.VerifyAll();
PublicVirtualMethod の動作を基底クラス SampleClass のまま(true を返す)にしたい場合は、以下のようにします。
mock.CallBase = true; // ★Setup で定義した呼び出し以外は基底クラスの動作とする。

Assert.IsFalse(sample.PublicVirtualProperty); // Setup したメソッドの動作はオーバーライドされたまま。
Assert.IsTrue(sample.PublicVirtualMethod()); // ★基底クラスの仮想メソッドが呼ばれ、true が返る。

この CallBase の動作を前提に、メソッド呼び出し時の引数の値を動的に書き換えてみます。

// モックオブジェクト
Mock<SampleClass> mock = new Mock<SampleClass>();
mock.CallBase = true; // Setup で定義した呼び出し以外は基底クラスの動作を保持
SampleClass sample = mock.Object;

// 書き換え後の引数値
string hackArg = "HackArg";

// オーバーライド
//  引数が hackArg と異なる場合は WriteArg メソッドの動作をオーバーライドする。
//  オーバーライドされた場合、Callback で引数を hackArg に変えて基底クラスの仮想メソッドを呼び出す。
mock.Setup(s => s.WriteArg(It.Is<string>(arg => arg != hackArg)))
  .Callback<string>((arg) => sample.WriteArg(hackArg)); // It.Is に該当しないので基底クラスのメソッドが実行される。

// 実行
sample.WriteArg("OriginalArg");
// → 「WriteArg が引数 "HackArg" で呼ばれました。」

// 検証
mock.VerifyAll();
ストレートな方法でないのが少し残念です。
上の例は単純化して WriteArg を直接実行しているのであまり実用的ではありませんが、
間接的に呼び出されるメソッドの引数値をテスト用に変える、といったことが可能になります。
モックライブラリ Moq と DIコンテナ Unity を使用してモック化する例です。
単体テストの基底クラスにモックの生成、確認(Verify)を実装することで、素早く、すっきりテストコードを書くことができます。
※Unity は Microsoft patterns & practices の手を離れ、オープンソースで運営されていましたが、最終リリースが 2015年10月6日 で止まっています。

▼プロダクションコード
/// <summary>
/// Unity のヘルパー。
/// </summary>
internal static class UnityHelper
{
    /// <summary>
    /// 親コンテナ。
    /// </summary>
    /// <remarks>毎回デフォルトコンストラクタで生成する。</remarks>
    private static readonly IUnityContainer parentContainer = CreateTransientContainer();

    /// <summary>
    /// 親コンテナ(毎回デフォルトコンストラクタで生成)を基にした子コンテナを生成する。
    /// </summary>
    /// <returns></returns>
    public static IUnityContainer CreateTransientBasedContainer()
    {
        return parentContainer.CreateChildContainer();
    }

    /// <summary>
    /// 毎回デフォルトコンストラクタで生成するコンテナを用意する。
    /// </summary>
    /// <returns></returns>
    private static IUnityContainer CreateTransientContainer()
    {
        var container = new UnityContainer();

        container.RegisterTypes(
            AllClasses.FromLoadedAssemblies(),
            WithMappings.FromMatchingInterface,
            WithName.Default,
            t => new TransientLifetimeManager());

        return container;
    }
}

/// <summary>
/// テスト対象システム。
/// </summary>
public class SystemUnderTest
{
    /// <summary>
    /// DIコンテナ。
    /// </summary>
    internal IUnityContainer DiContainer { get; set; } = UnityHelper.CreateTransientBasedContainer();

    /// <summary>
    /// コンストラクタ。
    /// </summary>
    public SystemUnderTest()
    {
        // 毎回デフォルトコンストラクタで生成する場合、何もしない。

        // テスト対象オブジェクト内で一つのインスタンスを共用する場合、RegisterInstance する。
        this.DiContainer.RegisterInstance<DependOnComponent>(new DependOnComponent());

        /* 毎回の生成ロジックを調整するなら InjectionFactory 指定で RegisterType する。
        this.UnityContainer.RegisterType<DependOnComponent>(
            new InjectionFactory(c => {
                return new DependOnComponent("Production_InjectionFactory");
            }));
        */
    }

    /// <summary>
    /// テスト対象メソッド。
    /// </summary>
    /// <returns></returns>
    public string GetText()
    {
        // DIコンテナから依存オブジェクトを取得する。
        // ※RegisterInstance で一つのインスタンスを使用する場合、ショートカット的にプロパティを定義してもよい。
        var component = this.DiContainer.Resolve<DependOnComponent>();

        return component.GetText();
    }
}

/// <summary>
/// 依存コンポーネント。
/// </summary>
public class DependOnComponent
{
    private readonly string text = "Production";

    public DependOnComponent()
    {
    }

    public DependOnComponent(string text)
    {
        this.text = text;
    }

    public virtual string GetText()
    {
        return this.text;
    }
}
▼単体テスト
/// <summary>
/// 単体テストの基底クラス。
/// </summary>
public abstract class UnityTestBase
{
    /// <summary>
    /// モックオブジェクトのリスト。
    /// </summary>
    private List<Mock> mocks;

    /// <summary>
    /// 単体テスト用にモックオブジェクトを提供するDIコンテナ。
    /// </summary>
    internal IUnityContainer DiContainer { get; private set; }

    /// <summary>
    /// テストの初期処理。
    /// </summary>
    [TestInitialize]
    public void BaseTestInitialize()
    {
        this.DiContainer = new UnityContainer();
        this.mocks = new List<Mock>();
    }

    /// <summary>
    /// テストの終了処理。
    /// </summary>
    [TestCleanup]
    public void BaseTestCleanup()
    {
        // モックが期待どおりに呼び出されたことを検証する。
        foreach (var mock in this.mocks)
        {
            mock.VerifyAll();
        }

        this.DiContainer.Dispose();
    }

    /// <summary>
    /// Mock インスタンスを生成する。
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    protected Mock<T> CreateMock<T>()
        where T : class
    {
        return CreateMock<T>(false);
    }

    /// <summary>
    /// Mock インスタンスを生成する。
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="callBase"></param>
    /// <returns></returns>
    protected Mock<T> CreateMock<T>(bool callBase)
        where T : class
    {
        var mock = new Mock<T> { CallBase = callBase };

        this.DiContainer.RegisterInstance(mock.Object);
        this.mocks.Add(mock);

        return mock;
    }

    /// <summary>
    /// テスト用のDIコンテナを取得する。
    /// </summary>
    /// <returns></returns>
    protected IUnityContainer GetDiContainer()
    {
        return this.DiContainer;
    }
}

/// <summary>
/// 単体テスト。
/// </summary>
/// <remarks>
/// モックをDIコンテナに詰めて渡すので、依存コンポーネントをモックに差し替えるためだけに
/// SystemUnderTest を継承した Testable クラスを用意する必要はない。
/// Autofac に切り替えるときは基底クラスを AutofacTestBase に変える(テストコードは同一)。
/// </remarks>
[TestClass]
public class UnitTest : UnityTestBase
{
    [TestMethod]
    public void GetText_Mocking()
    {
        // モック設定
        var componentMock = CreateMock<DependOnComponent>();
        componentMock.Setup(c => c.GetText()).Returns("UnitTest");

        // テスト対象オブジェクトを生成(モック用のDIコンテナを設定)
        var system = new SystemUnderTest { DiContainer = GetDiContainer() };
        string text = system.GetText();

        Assert.AreEqual("UnitTest", text);
    }
}
モックライブラリ Moq と IoCコンテナ Autofac を使用してモック化する例です。
単体テストの基底クラスにモックの生成、確認(Verify)を実装することで、素早く、すっきりテストコードを書くことができます。

▼プロダクションコード
/// <summary>
/// テスト対象システム。
/// </summary>
public class SystemUnderTest
{
    /// <summary>
    /// DIコンテナ。
    /// </summary>
    internal IContainer DiContainer { get; set; }

    /// <summary>
    /// コンストラクタ。
    /// </summary>
    public SystemUnderTest()
    {
        var containerBuilder = new ContainerBuilder();

        /* Resolve のたびにインスタンスを生成する場合
        builder.Register(c => new DependOnComponent("Production_PerDependency")).InstancePerDependency();
        */

        // テスト対象オブジェクト内で一つのインスタンスを共用する場合
        containerBuilder.Register(c => new DependOnComponent()).SingleInstance();

        this.DiContainer = containerBuilder.Build();
    }

    /// <summary>
    /// テスト対象メソッド。
    /// </summary>
    /// <returns></returns>
    public string GetText()
    {
        // DIコンテナから依存オブジェクトを取得する。
        // ※SingleInstance の場合、ショートカット的にプロパティを定義してもよい。
        var component = this.DiContainer.Resolve<DependOnComponent>();

        return component.GetText();
    }
}

/// <summary>
/// 依存コンポーネント。
/// </summary>
public class DependOnComponent
{
    private readonly string text = "Production";

    public DependOnComponent()
    {
    }

    public DependOnComponent(string text)
    {
        this.text = text;
    }

    public virtual string GetText()
    {
        return this.text;
    }
}
▼単体テスト
/// <summary>
/// 単体テストの基底クラス。
/// </summary>
public abstract class AutofacTestBase
{
    /// <summary>
    /// モックオブジェクトのリスト。
    /// </summary>
    private List<Mock> mocks;

    /// <summary>
    /// 単体テスト用にモックオブジェクトを提供するDIコンテナのビルダー。
    /// </summary>
    internal ContainerBuilder DiContainerBuilder { get; private set; }

    /// <summary>
    /// テストの初期処理。
    /// </summary>
    [TestInitialize]
    public void BaseTestInitialize()
    {
        this.DiContainerBuilder = new ContainerBuilder();
        this.mocks = new List<Mock>();
    }

    /// <summary>
    /// テストの終了処理。
    /// </summary>
    [TestCleanup]
    public void BaseTestCleanup()
    {
        // モックが期待どおりに呼び出されたことを検証する。
        foreach (var mock in this.mocks)
        {
            mock.VerifyAll();
        }
    }

    /// <summary>
    /// Mock インスタンスを生成する。
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    protected Mock<T> CreateMock<T>()
        where T : class
    {
        return CreateMock<T>(false);
    }

    /// <summary>
    /// Mock インスタンスを生成する。
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="callBase"></param>
    /// <returns></returns>
    protected Mock<T> CreateMock<T>(bool callBase)
        where T : class
    {
        var mock = new Mock<T> { CallBase = callBase };

        this.DiContainerBuilder.RegisterInstance(mock.Object);
        this.mocks.Add(mock);

        return mock;
    }

    /// <summary>
    /// テスト用のDIコンテナを取得する。
    /// </summary>
    /// <returns></returns>
    protected IContainer GetDiContainer()
    {
        return this.DiContainerBuilder.Build();
    }
}

/// <summary>
/// 単体テスト。
/// </summary>
/// <remarks>
/// モックをDIコンテナに詰めて渡すので、依存コンポーネントをモックに差し替えるためだけに
/// SystemUnderTest を継承した Testable クラスを用意する必要はない。
/// Unity に切り替えるときは基底クラスを UnityTestBase に変える(テストコードは同一)。
/// </remarks>
[TestClass]
public class UnitTest : AutofacTestBase
{
    [TestMethod]
    public void GetText_Mocking()
    {
        // モック設定
        var componentMock = CreateMock<DependOnComponent>();
        componentMock.Setup(c => c.GetText()).Returns("UnitTest");

        // テスト対象オブジェクトを生成(モック用のDIコンテナを設定)
        var system = new SystemUnderTest { DiContainer = GetDiContainer() };
        string text = system.GetText();

        Assert.AreEqual("UnitTest", text);
    }
}
単体テストやログ出力に便利な Reflection のスニペットを集めてみました。
// ▼インスタンス生成
{ // public/引数なし
	Sample sample = Activator.CreateInstance<Sample>();
}
{ // public/引数あり
	object[] args = new object[]{ true };
	Sample sample = (Sample)Activator.CreateInstance(typeof(Sample), args);
}
{ // 非public/引数あり
	Type[] argTypes = new Type[]{ typeof(int) };
	ConstructorInfo constructor = typeof(Sample).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, argTypes, null);
	object[] args = new object[]{ 1 };
	Sample sample = (Sample)constructor.Invoke(args);
}

// ▼フィールドアクセス
{ // 非public/インスタンスフィールド(静的フィールドの場合、BindingFlags.Instance → BindingFlags.Static)
	Sample sample = new Sample();
	FieldInfo field = sample.GetType().GetField("_privateField", BindingFlags.NonPublic | BindingFlags.Instance);
	field.SetValue(sample, true);
	bool fieldValue = (bool)field.GetValue(sample);
}

// ▼プロパティアクセス
{ // 非public/インスタンスプロパティ(静的プロパティの場合、BindingFlags.Instance → BindingFlags.Static)
	Sample sample = new Sample();
	PropertyInfo property = sample.GetType().GetProperty("PrivateProperty", BindingFlags.NonPublic | BindingFlags.Instance);
	property.SetValue(sample, true, null);
	bool propertyValue = (bool)property.GetValue(sample, null);
}

// ▼メソッド実行
{ // 非public/インスタンスメソッド
	Sample sample = new Sample();
	MethodInfo method = sample.GetType().GetMethod("PrivateMethod", BindingFlags.NonPublic | BindingFlags.Instance);
	object[] args = new object[]{ 1 };
	bool returnValue = (bool)method.Invoke(sample, args);
}
{ // ref 引数
	Sample sample = new Sample();
	Type[] paramTypes = new Type[] { typeof(bool).MakeByRefType() };
	MethodInfo method = sample.GetType().GetMethod("ReceiveByRefArgument", BindingFlags.NonPublic | BindingFlags.Instance, null, paramTypes, null);
	bool inValue = false;
	object[] args = new object[] { inValue };
	method.Invoke(sample, args);
	bool outValue = (bool)args[0];
}

// ▼属性情報
{
	SampleAttribute attribute = (SampleAttribute)Attribute.GetCustomAttribute(typeof(Sample), typeof(SampleAttribute));
	bool AttributeProperty = attribute.Foo;
}

// ▼アセンブリ情報
{
	Assembly executingAssembly = Assembly.GetExecutingAssembly(); // 現在実行中のコードを格納しているアセンブリ
	Assembly callingAssembly   = Assembly.GetCallingAssembly();   // 現在実行中のメソッドを呼び出したメソッドのアセンブリ
	Assembly entryAssembly	 = Assembly.GetEntryAssembly();	 // 実行ファイルのアセンブリ(アンマネージアプリケーションから読み込まれている場合、null)
	string exePath = Application.ExecutablePath; // 実行ファイルのパス
}

// ▼型情報
{
	Type type = typeof(Sample);
	bool isEnum = type.IsEnum; // 列挙型か。
	bool isValueType = type.IsValueType; // 値型か。
	bool isNullableValueType = (Nullable.GetUnderlyingType(type) != null); // Nullを許可する値型か。
}
{ // 型名
	Assert.AreEqual("String", typeof(String).Name);
	// C# 6.0 / VB 2015 ~
	Assert.AreEqual("String", nameof(String));
}

// ▼メソッド情報
{ // 現在のメソッド名
	string currentMethodName = MethodBase.GetCurrentMethod().Name;
}
{ // 呼び出し元のメソッド名
 // ※コンパイラによってインライン展開されていないことが前提です。
  // ※.NET 4.5 では、CallerMemberNameAttribute で引数から取得できます。
	StackFrame frame = new StackFrame(1);
	string callerMethodName = frame.GetMethod().Name;
}
{ // メソッド名
	// C# 6.0 / VB 2015 ~
	Assert.AreEqual("IndexOf", nameof(String.IndexOf));
}

// ▼プロパティ情報
// 現在のプロパティ名
public bool Property {
	get {
		MethodBase accessor = MethodBase.GetCurrentMethod();
		string propertyName = GetProperty(accessor).Name;
		return true;
	}
}
// アクセサメソッドからプロパティを取得する。
public static PropertyInfo GetProperty( MethodBase accessor )
{
	PropertyInfo[] properties = accessor.DeclaringType.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
	foreach( PropertyInfo property in properties ) {
		MethodInfo[] methods = property.GetAccessors(true);
		foreach( MethodInfo method in methods ) {
			if( method == accessor ) return property;
		}
	}
	return null;
}
{ // プロパティ名
	// C# 6.0 / VB 2015 ~
	Assert.AreEqual("Length", nameof(String.Length));
}

    
▼四捨五入で端数処理した税込価格 → 本体価格
// C#
Math.Ceiling((priceWithTax - 0.5m) / (1m + rate))
' VB.NET
Math.Ceiling((priceWithTax - 0.5D) / (1D + rate))
▼切り捨てで端数処理した税込価格 → 本体価格
// C#
Math.Ceiling(Math.Abs(priceWithTax) / (1m + rate)) * (priceWithTax >= 0 ? 1 : -1)
' VB.NET
Math.Ceiling(Math.Abs(priceWithTax) / (1D + rate)) * If(priceWithTax >= 0, 1, -1)
▼切り上げで端数処理した税込価格 → 本体価格
// C#
Math.Truncate(priceWithTax / (1m + rate))
' VB.NET
Math.Truncate(priceWithTax / (1D + rate))
※rate には、0.05m, 0.08m などの消費税率(正の値)が入ります。
▼.NET Framework
『Essential .NET ― 共通言語ランタイムの本質』(Don Box, Chris Sells 著)
 .NET の仕組みについて突っ込んだ解説がされています。
 2001年頃、.NET 1.0 を対象に書かれた本ですが、今も変わらないコアな技術の話で構成されています。

▼プラクティス
『.NETのクラスライブラリ設計』(Krzysztof Cwalina, Bard Abrams 著)
 「良い設計のフレームワーク」を作成するためのガイドライン、プラクティス、アンチパターンをまとめたものです。
 個々のガイドラインに対し、Jeffrey Richer, Chris Anderson, Chris Sells ら多数の寄稿者による注釈が付記されています。
 重点が少し異なるところもありますが、基本的にはアプリケーション開発者にとっても役立つ汎用的な内容です。
 Visual Studio のコード分析機能(参考:コード標準化支援)に実装されているものも多くあります。

『C# 実践開発手法 ~デザインパターンとSOLID原則によるアジャイルなコーディング』(Gary McLean Hall 著)
 「アジャイルの基礎」「SOLID コードの記述」「アダプティブサンプル」の三部構成で、「適応力のあるコード」を目指す本です。
 オブジェクト指向設計の SOLID 原則について書かれた第2部は、アジャイルに関係なくお勧めです。
 デザインパターンや .NET の言語サポートと絡め、各原則の実用的な意義がサンプルコード付きでわかりやすく解説されています。

▼WPF
『エッセンシャル WPF』(Chris Anderson 著)
 WPFチームのチーフアーキテクトがWPFの基本概念について解説したものです。
 WPFの心がわかります(WPFが目指したことの理解に役立ちます)。

『プログラミング Windows 第6版 上』(Charles Petzold 著)
 副題に「C#とXAMLによるWindowsストアアプリ開発」とあるとおり、ストアアプリを対象としていますが、多くの部分はWPFにも(一部読み替えて)適用できます。
 (参考:プログラミング Windows 第6版 WPF編)
 そこそこの分量(720ページ)があって章立ても網羅的なことから、辞書的に使おうとお考えになるかもしれませんが、通読に向いています。
 MVVM についても一章割かれています。

▼ASP.NET MVC
『プログラミング Microsoft ASP.NET MVC』(Dino Esposito 著)
 APIの解説から具体的な実装手法、アーキテクチャまで。ユニットテストにも一章割かれています。

▼Entiity Framework
『Programming Entity Framework』(Julia Lerman 著)
 英語ですが、日本語の本がない(ネットの情報も少ない)現状では、頑張って読む価値があります。
 あまり知られていないソリューションがコード付きで紹介されていたりするので、興味のあるトピックを拾い読みするだけでも役に立つと思います。

▼非同期処理
『C#によるマルチコアのための非同期/並列処理プログラミング』(山本 康彦 著)
 .NET 1.x から .NET 4.5 までの非同期処理技術の進化を、豊富なサンプルコードとともにわかりやすく解説しています。
 ThreadPool~APM(Asynchronous Programming Model)~EAP(Event-based Asynchronous Pattern)~TAP(Task-based Asynchronous Pattern)~async/await

▼ユニットテスト
『The Art of Unit Testing: with examples in C#』(Roy Osherove 著)
 依存性の切り離し方、モックライブラリの使い方から、テストクラスのパターン/アンチパターンまで。
 「モックとスタブの違いは?」といったトピックもあります。

▼番外編
『ADO 集中講座』(Rob Macdonald 著)
 ADO.NET ではなく、ADO の本です。
 (出番はかなり少なくなりましたが、VBA や古いアプリケーションの保守など、まだまだ活躍する機会はあるでしょう。)
  Redordset の高速な操作、階層化... ADO を使い尽くすことができます。

『標準 FindBugs 完全解説』(宇野るいも, arton 著)
 Java 用のバグ発見(静的解析)ツールのルール解説書です。
 各ルールについて、なぜそれが潜在的なバグなのか、丁寧に説明されており、.NET プログラマにも得るところがあります。
 よいプラクティスの生まれる一つの源になるかもしれません。
 誰よりもバグが嫌いな方にお勧めです。

『オフショア開発に失敗する本』(幸地 司 著)
 文化、常識の異なる人たちと一つの物を作り上げるときの心構えが学べます。
 事例も教科書的でなく現場に即したもので、発注側/受注側双方の立場、気持ちの理解に役立ちます。
 2008年刊行のため、業界の動向に関する記載に古い点もありますが、
 オフショア開発はもちろんのこと、国内のアウトソーシングや国際交流一般にも応用できる内容です。
「データを削除してよろしいですか?」
業務システムでは様々な場面でこのようなメッセージが必要になります。

メッセージ管理は悩ましい問題の一つです。
言い回しや文言は統一したい。
プログラマの自由に任せれば、あるいところでは「削除しますか?」が
別のところで「削除します。よろしいですか。」になったりして、統一感が失われてしまいます。

そこで出てくるのがメッセージのID管理です。
多くのシステムで利用されており、皆さんも一度は使われたことがあるはずです。
IDと埋め字付きメッセージ文字列がテキストファイルやリソースファイルに

Q003={0}を削除してよろしいですか?
のように定義され、IDを指定するとメッセージ文字列を取得できる仕組みが用意されます。
表現の見直し、ローカライズも比較的容易です。

ただ、この方法にもデメリットがあります。

if (!this.MessageBoxService.ShowYesNo(MessageResource.GetText("Q003", "データ")))
{
	return;
}
これを見ただけではどんなメッセージが表示されるかわかりません。
メッセージ定義ファイルを確認して初めてわかります。
それでは効率・可読性が悪いので、コメントをつけたりします。

// Q003={0}を削除してよろしいですか?
if (!this.MessageBoxService.ShowYesNo(MessageResource.GetText("Q003", "データ")))
{
	return;
}
しかし、その後メッセージ定義を変えると、コメントが実際と違ってしまいます。

メッセージをクラスで管理することにより、これらを解消することができます。
使用例から見てみましょう。

if (!this.MessageBoxService.ShowYesNo(Messages.Action.ConfirmDelete("データ")))
{
	return;
}
IDではなく、わかりやすく命名したメソッドで識別します。
メソッド定義は次のようになります。

[MessageFormat("{0}を削除してよろしいですか?")]
public static string ConfirmDelete(string target)
{
    return GetText(target);
}
メッセージ文字列はカスタム属性で定義しているので、使用箇所から参照するのも簡単です。
(メッセージファイルを開いてIDで検索する必要がありません。)

GetText メソッドでは、カスタム属性を解析してメッセージ文字列を生成します。
(コンパイラの最適化によるインライン展開を防いだうえで、StackFrame から呼出元メソッドの情報を取得します。)
クラス名、メソッド名をキーにリソース定義することで、ローカライズも可能です。

ローカライズが不要な場合でも、カスタム属性やリソースに定義しておくことで、
インラインのリテラルでメッセージを記述するよりもドキュメント化がしやすくなります。
言語によって null の扱いは異なりますので注意が必要です。
以下に例を示します。
C# VB.NET SQL (ANSI)
string nullString = null; Dim nullString As String = Nothing
Equals Equals(nullString, null)
true
Equals(stringNulll, Nothing)
True
Is (nullString Is Nothing)
True
(nullString IS NULL)
TRUE
Is Not (nullString IsNot Nothing)
False
(nullString IS NOT NULL)
FALSE
等号(null との比較) (nullString == null)
true
(nullString = Nothing)
True
(nullString = NULL)
UNKNOWN (FALSE)
不等号(null との比較) (nullString != null)
false
(nullString <> Nothing)
False
(nullString <> NULL)
UNKNOWN (FALSE)
等号(空文字との比較) (nullString == "")
false
(nullString = "")
True
(nullString = '')
UNKNOWN (FALSE)
不等号(空文字との比較) (nullString != "")
true
(nullString <> "")
False
(nullString <> '')
UNKNOWN (FALSE)
不等号(有効文字との比較) (nullString != "a")
true
(nullString <> "a")
True
(nullString <> 'a')
UNKNOWN (FALSE)
※LINQ to Entities の値比較における null の扱いには別途注意が必要です。
 Entity Framework 6 では UseDatabaseNullSemantics プロパティ が導入され、既定(False)で生成されるSQLも変更されました。
▼.NET共通(的)
 
 DirectCast
 ・CType より速い。
 ・参照型であればダウンキャスト、値型であればアンボクシングする。
 
 CType
 ・DirectCast より遅い。
 ・暗黙の型互換があればOK(なければ実行時例外)。
 ・配列データ型を変換することもできる。
 ・VB.NET の CType 関数と C# のキャスト演算子とでは、結果が異なる場合がある。
  Single 型から Int32 型に変換する場合、CType 関数では小数点以下を銀行型丸め(近い方の整数に丸める。0.5 は偶数になるように丸める)によって取り除くが、C# では切り捨てられる。
 
 TryCast
 ・参照型のみ。
 ・C# の as に相当。
 
 ToString
 ・文字列化。
 ・Enum の ToString() はメンバ名になる。
 ・Decimal の ToString で末尾のゼロを取り除く(1.0 → "1")には、書式 "G29" を指定する。(.NET 1.1 以上の場合)
 
 ボックス化(値型を Object など参照型に代入)
 ・参照型として扱われるだけで、ByVal では値のコピーが渡される。
 ・元の型にしかボックス化解除できない。
  (異なる型へボックス化解除すると、キャストなしの暗黙型変換が可能でも InvalidCastException が発生する)
 
 Parse, ParseExact, TryParse
 ・文字列から変換。
 ・DateTime 型の場合、ParseExact で書式を明示指定して変換することができる。
 ・Nothing を渡すと ArgumentNullException が発生する。
 ・TryParse するたびに result 用の変数を宣言しているとコードが冗長になる。
  以下のような共通メソッドを用意して、ParseInt(s, 0) のように使用するとコードがすっきりする。
Public Shared Function ParseInt(ByVal s As String) As Nullable(Of Integer)

    Dim result As Integer
    If Integer.TryParse(s, NumberStyles.Any, Nothing, result) Then
        Return result
    Else
        Return Nothing
    End If

End Function

Public Shared Function ParseInt(ByVal s As String, ByVal ifInvalid As Integer) As Integer

    Return If(ParseInt(s), ifInvalid)

End Function
 
 Convert クラス
 ・基本データ型を別の基本データ型に変換する。
 ・内部的に Parse メソッドを呼んでいる。
 ・銀行型丸め。
 
 TypeConverter クラス
 ・コントロールのデザインプロパティの文字列解析などに使用されている。
 ・TypeDescriptor.GetConverter(Type) メソッドで、実行時に型(Type オブジェクト)を指定して TypeConverter オブジェクトを取得することができる。
 ・ConvertFromString(String) メソッドなどが用意されているが、許容範囲は狭い。
  桁区切りカンマ、通貨記号、大文字は数値の構成要素として解釈されず、小数から整数へのキャストもできない。
 
▼VB特有
 
 データ型変換関数(CStr, CInt, ...)
 ・CInt(o) と CType(o , Integer) は等価。
 ・CInt(CType)の小数→整数は銀行型丸め。
 
 Int
 ・負の値で切り捨てにならない。
  負でも切り捨てるには Fix 関数を使いましょう。
 
 Val
 ・手軽な反面、意図しない結果になることがあるので、使用には注意が必要。
 
 Option Strict Off
  Off だと意図しない型変換が自動的に行われ、バグの温床になる。
  On にすることが推奨されている。
例えば、DataTable.Rows プロパティの戻り値型 DataRowCollection は IEnumerable を実装していますので、
foreach( DataRow row in table.Rows ) {}
のように列挙させることができます。
列挙できるなら LINQ で扱いたいですね。
しかし、table.Rows. と打っても LINQ の拡張メソッドは候補表示されません。
LINQ で扱うためには、ジェネリックインターフェイスの IEnumerable<T> に変換する必要があります。
変換するには Enumerable.Cast<TResult> 拡張メソッドを使用します。
以下の3つの処理はいずれも等価です。
// メソッド構文
var rowsByMethod = table.Rows.Cast<DataRow>().Where(row => row.IsNull(0));
// クエリ構文1
var rowsByQuery1 = from row in table.Rows.Cast<DataRow>() where row.IsNull(0) select row;
// クエリ構文2(暗黙的に Cast<DataRow>() が呼ばれます)
var rowsByQuery2 = from DataRow row in table.Rows where row.IsNull(0) select row;
System.Data.DataSetExtensions を参照設定に追加すると、以下のように記述することもできます。
var rowsByTable = table.AsEnumerable().Where(row => row.IsNull(0));

非ジェネリックコレクションの ArrayList も(使われる機会はあまりなくなりましたが)、
Cast することで LINQ で扱うことができます。
ただし、キャストできない型の要素が含まれると、実行時例外の原因となりますので注意が必要です。
さて、ここで問題です。次のコードを実行するとどうなるでしょうか。
ArrayList list = new ArrayList();
list.Add(0);
list.Add("a");

IEnumerable<int> query = list.Cast<int>();
bool hasItems = query.Any();
正解は、InvalidCastException が発生する――ではありません。
hasItems が true になって正常終了します。
なぜでしょうか。
それは、Cast が遅延評価される(必要になったときに実行される)からです。
Any は要素が1つでもあれば true を返しますので、1つ目の要素しか見ません。
したがって、2つ目の要素 "a" は Cast されずに終わります。
この後、例えば query.Count() を実行すると、そこで初めて InvalidCastException が発生します。
※int 型にキャスト可能な要素のみを取得したい場合は、Cast<int>() の代わりに OfType<int>() を使用します。
DataTable 内の行を抽出するにはいくつか方法があり、それぞれに特徴を持っています。
大量のデータを対象とする場合、メモリ上に作成されるインデックスの有無でパフォーマンスにかなりの差が出ます。

DataTable
  Rows.Find :
    PrimaryKey で検索。PrimaryKey には自動的にインデックスが付与される。
  FindBy... :
    型付DataSetで主キー検索する場合。
  Select :
    PrimaryKey や DataView によりインデックスが作成済みであればそれを利用するので高速になる。
 
DataView
  Sort プロパティ :
    指定列にインデックスが作成される。
  RowFilter プロパティ :
    既にインデックスが存在すれば使用する。
    Sort プロパティが未指定の場合、(列ではなくて)指定した式の処理が高速化されるよう、インデックスが作成される。
  Find メソッド :
    DataView 内を Sort 列の値で検索する。
  FindRows メソッド :
    Find メソッドの複数行版。
 
※DataView のインデックスは コンストラクタで構築されるほか、RowFilter/Sort プロパティ設定のたびに再構築されます。
 無駄のないように、RowFilter/Sort はコンストラクタで指定するようにしましょう。
※DataView の操作によって作成されたインデックスは Dispose されるまで有効で、
 同じDataTable に対する別の DataView 操作にも適用されます。
※値比較の際、大文字/小文字、全角/半角を区別するには、CaseSensitive を true にしましょう。
大量のデータを高速に投入する方法として、
SQL Server には BULK INSERT ステートメントや bcp ユーティリティが用意されていますが、
これらはテキストファイルしか読めないうえ、文字列を囲む引用符を外すには FORMATFILE の作成が必要など、
決して使い勝手がよいとは言えません。

ADO.NET の SqlBulkCopy クラス を使用すると、
DataReader や DataTable から高速にデータを投入することができます。

基本的な使い方は簡単です。
// C#
using( SqlConnection cn = new SqlConnection(connectionString) )
{
    cn.Open();
    
    using( SqlBulkCopy bulkCopy = new SqlBulkCopy(cn) )
    {
        bulkCopy.DestinationTableName = "FooTable";
        bulkCopy.WriteToServer(source); // source: DataReader/DataTable/DataRow[]
    }
}
'VB.NET
Using cn As New SqlConnection(connectionString)
    cn.Open()
    
    Using bulkCopy As New SqlBulkCopy(cn)
        bulkCopy.DestinationTableName = "FooTable"
        bulkCopy.WriteToServer(source) 'source: DataReader/DataTable/DataRow()
    End Using
End Using
ただし、これだけだと意図した動作が実現できない場合が出てきます。
ケースに応じた対処方法と注意点を、以下に記載します。

○コピー元とコピー先で列数や列順が異なる場合は、
 ColumnMappings.Add("BarColumn", "BarColumn") のように、列を対応づけておく必要があります。
 (たとえば、DataTable が Expression 列を含む場合、それらを除いた列を明示的に指定します。)
○タイムアウトが発生する場合、BulkCopyTimeout プロパティに適切な値を設定します。
 既定では 30 秒でタイムアウトになります。
 タイムアウトを発生させたくないときは、BulkCopyTimeout プロパティに 0 を指定します。
○BatchSize プロパティで一度に処理する行数を設定し、パフォーマンスを上げることができます。
 ただし、一度に処理するデータが多すぎると、BulkCopyTimeout を 0 に設定してもタイムアウトが発生することがあります。
○既定では、コピー元の Identity 列値は無視され、新たに連番が振られます。
 Identity 列値を保持する場合は、SqlBulkCopy のコンストラクタで SqlBulkCopyOptions.KeepIdentity を指定します。
○処理時間が長いと、デバッグ実行で ContextSwitchDeadLock が発生することがありますが、[続行] を押すと処理が続行されます。
 ContextSwitchDeadLock の発生自体を抑止するには、
 [デバッグ] - [例外] から [Managed Debugging Assistants] の [ContextSwitchDeadLock] をオフにします。
データ作成/更新日時など管理列の値設定は共通処理にすると便利です。
Entity Framework ではどのタイミングでどのように設定すればよいでしょうか。
(データベースのトリガーにしないこと、ローカルのシステム日付を使用することの是非についてはここでは触れません。)

方法はいくつかあります。

○データバインドコントロールのイベント
 ASP.NET Web フォームの場合、以下のハンドラで
 e.Values(Insert の場合)または e.NewValues(Update の場合)の各カラム要素に値を設定すると反映されます。
  ・GridView.RowUpdating イベント
  ・ListView.ItemInserting/ItemUpdating イベント
  ・DetailsView.ItemInserting/ItemUpdating イベント
  ・FormView.ItemInserting/ItemUpdating イベント

○データソースコントロールのイベント
 ASP.NET Web フォームの場合、以下のハンドラでエンティティを取得してプロパティに設定することができます。
  ・ObjectDataSource.Inserting/Updating イベント
   e.InputParameters[0] にエンティティが格納されています。
  ・EntityDataSource.Inserting/Updating イベント
   e.Entity にエンティティが格納されています。
 
○SaveChanges メソッド(dynamic 方式)
 個別のデータや操作に依存した値を設定するのには向きませんが、データ作成/更新日時の設定であれば、
 今回ご紹介した中で最も確実で実装効率のよい方法と言えます。
 ここでは DbContext(EF 4.1 ~)の SaveChanges メソッドをオーバーライドして作成日時を設定する例をご紹介します。
 (DbContext の部分クラスを作成して定義します。)
public partial class SampleEntities
{
	public override int SaveChanges()
	{
		SetCreatedDateTime();

		return base.SaveChanges();
	}

	private void SetCreatedDateTime()
	{
		DateTime now = DateTime.Now;

		// 追加エンティティのうち、CreatedDateTime プロパティを持つものを抽出
		var entities = this.ChangeTracker.Entries()
			.Where(e => e.State == EntityState.Added && e.CurrentValues.PropertyNames.Contains("CreatedDateTime"))
			.Select(e => e.Entity);

		foreach (dynamic entity in entities)
		{
			entity.CreatedDateTime = now;
		}
	}
}
○SaveChanges メソッド(インターフェイス方式)
 エンティティの部分クラス定義(インターフェイス実装)を手動で行う必要がありますが、dynamic 方式よりきれいです。
 エンティティを追加したときなど、部分クラス定義を忘れないように注意が必要です。
 (対策として、アプリケーション起動時やユニットテストでリフレクションを使って実装漏れを検出することなどが考えられます。)
// エンティティのインターフェイス
public interface IEntity
{
    int? CreatedUserId { get; set; }
    DateTime? CreatedDateTime { get; set; }
    int? UpdatedUserId { get; set; }
    DateTime? UpdatedDateTime { get; set; }
}
// エンティティの部分クラス定義(例えば EntityPartials.cs など)
public partial class Foo : IEntity {}
public partial class Bar : IEntity {}
 : 
// DbContext の部分クラス定義
public partial class SampleEntities
{
	public override int SaveChanges()
	{
		SetCreatedDateTime();

		return base.SaveChanges();
	}

	private void SetCreatedDateTime()
	{
		DateTime now = DateTime.Now;

		// 追加エンティティのうち、IEntity を実装したものを抽出
		var entities = this.ChangeTracker.Entries()
			.Where(e => e.State == EntityState.Added)
			.Select(e => e.Entity)
			.OfType<IEntity>();
		
		foreach (var entity in entities)
		{
			entity.CreatedDateTime = now;
		}
	}
}
// IEntity の実装漏れを検出するユニットテスト
[TestMethod]
public void EntitiesShouldImplementIEntity()
{
	var entityTypes = typeof(SampleEntities)
		.GetProperties(BindingFlags.Public | BindingFlags.Instance)
		.Where(p => p.PropertyType.IsGenericType && p.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>))
		.Select(p => p.PropertyType.GetGenericArguments().Single());

	foreach (var type in entityTypes)
	{
		if (type == typeof(Baz))
		{
			// 除外エンティティ
			continue;
		}

		Assert.IsTrue(typeof(IEntity).IsAssignableFrom(type), String.Format("{0} は IEntity を実装していません。", type.FullName));
	}
}
Entity Framework のコンテキストにおいて、トランザクションは、
既定では SaveChanges() を実行したときに暗黙的に使用されます。

要件によっては、トランザクションのスコープを明示的に制御したいこともあるでしょう。
ここでは EF4.1 以降の DbContext を例に、その方法をご紹介します。

▼複数回の SaveChanges() をまたぐトランザクション
// コンテキスト
using( var dbContext = new NorthwindEntities() )
{
	// SaveChanges() を実行するたびに接続が開閉されないよう、あらかじめ開いておく。
	((IObjectContextAdapter)dbContext).ObjectContext.Connection.Open();
	
	// TransactionScope で囲む。
	using( var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted }) )
	{
		// 1つめの SaveChanges()
		Product product = dbContext.Products.Single(p => p.ProductID == 1);
		product.ProductName = "New Product Name";
		dbContext.SaveChanges();
		
		// 2つめの SaveChanges()
		Employee employee = dbContext.Employees.Single(e => e.EmployeeID == 1);
		employee.Title = "New Title";
		dbContext.SaveChanges();
		
		// まとめてコミット
		scope.Complete();
	}
}
TransactionScope 内で例外が発生した場合は、トランザクションがロールバックされます。
※TransactionScope を使用するには、System.Transactions.dll を参照設定する必要があります。

▼複数のコンテキストをまたぐトランザクション
既存の接続をコンストラクタに指定してコンテキストを生成することによって、
複数のコンテキスト間で接続やトランザクションを共用することができます。
// 共用する接続の作成
using( var cn = new EntityConnection("name=NorthwindEntities") )
{
	// SaveChanges() を実行するたびに接続が開閉されないよう、あらかじめ開いておく。
	cn.Open();
	
	// TransactionScope で囲む。
	using( var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted }) )
	{
		// 1つめのコンテキスト(接続を指定して生成)
		using( var dbContext = new NorthwindEntities(cn, false) )
		{
			Product product = dbContext.Products.Single(p => p.ProductID == 1);
			product.ProductName = "New Product Name";
			dbContext.SaveChanges();
		}
		
		// 2つめのコンテキスト(接続を指定して生成)
		using( var dbContext = new NorthwindEntities(cn, false) )
		{
			Employee employee = dbContext.Employees.Single(e => e.EmployeeID == 1);
			employee.Title = "New Title";
			dbContext.SaveChanges();
		}
		
		// まとめてコミット
		scope.Complete();
	}
}

// コンテキストの部分クラス
public partial class NorthwindEntities : DbContext
{
	/// <summary>
	/// コンストラクタ。
	/// </summary>
	/// <param name="existingConnection">コンテキストで使用する接続。</param>
	/// <param name="contextOwnsConnection">false を指定すると、コンテキストが Dispose されたときに接続を Dispose しない。</param>
	public NorthwindEntities(DbConnection existingConnection, bool contextOwnsConnection)
		: base(existingConnection, contextOwnsConnection)
	{
	}
}

▼トランザクション直接操作
TransactionScope を使用せずに、DbTransaction オブジェクトを直接操作することも可能です。
using( var dbContext = new NorthwindEntities() )
{
	DbConnection cn = ((IObjectContextAdapter)dbContext).ObjectContext.Connection;
	cn.Open();

	// トランザクション開始
	using( DbTransaction tran = cn.BeginTransaction() )
	{
		try {
			Product product = dbContext.Products.Single(p => p.ProductID == 1);
			product.ProductName = "New Product Name";
			dbContext.SaveChanges();
			
			Employee employee = dbContext.Employees.Single(e => e.EmployeeID == 1);
			employee.Title = "New Title";
			dbContext.SaveChanges();
			
			// コミット
			tran.Commit();
		}
		catch {
			// ロールバック
			tran.Rollback();
			throw;
		}
	}
}

    
LINQ to Entities からデータベースの組み込み関数を呼び出すには、EntityFunctions クラス のメソッドを使用します。

たとえば、開始日から終了日までの日数を取得したいとき、
EntityFunctions.DiffDays(t.StartDate, t.EndDate)
のように記述すると、SQL Server であれば、
DATEDIFF (day, [Extent1].[StartDate], [Extent1].[EndDate])
のようなSQLに変換されます。

SQL Server 固有の組み込み関数を呼び出すには、SqlFunctions クラス のメソッドを使用します。

上記の日数取得は、SQL Server のみをターゲットに SqlFunctions で記述する場合、
SqlFunctions.DateDiff("day", t.StartDate, t.EndDate)
となります。
SQL Server の FILESTREAM はバイナリデータを管理するのに便利ですが、Entity Framework の Code First ではまだサポートされていません(2017年8月現在)。
Entity Framework Core では次の手順で FILESTREAM データにアクセスできるようになります。

1. インスタンスレベルで FILESTREAM を有効化します。
FILESTREAM の有効化と構成 | Microsoft Docs

2. FILESTREAM を有効化したデータベースを作成します。
FILESTREAM が有効なデータベースを作成する方法 | Microsoft Docs

3. モデルクラスに byte 配列型でプロパティを定義します。

4. パッケージマネージャーコンソールまたは CLI コマンドで初期マイグレーションを作成します。

5. Migrations フォルダ内にヘルパークラスを作成します。
public static class FileStreamHelper
{
	public static void UpTable(MigrationBuilder migrationBuilder, string tableName, string fileDataColumnName)
	{
		migrationBuilder.Sql($"ALTER TABLE [{tableName}] ADD [FsId] uniqueidentifier rowguidcol NOT NULL");
		migrationBuilder.Sql($"ALTER TABLE [{tableName}] ADD CONSTRAINT [UQ_{tableName}_FsId] UNIQUE NONCLUSTERED ([FsId])");
		migrationBuilder.Sql($"ALTER TABLE [{tableName}] ADD CONSTRAINT [DF_{tableName}_FsId] DEFAULT (NewID()) FOR [FsId]");
		migrationBuilder.Sql($"ALTER TABLE [{tableName}] DROP COLUMN [{fileDataColumnName}]");
		migrationBuilder.Sql($"ALTER TABLE [{tableName}] ADD [{fileDataColumnName}] varbinary(max) FILESTREAM NULL");
	}

	public static void DownTable(MigrationBuilder migrationBuilder, string tableName, string fileDataColumnName)
	{
		migrationBuilder.Sql($"ALTER TABLE [{tableName}] DROP COLUMN [{fileDataColumnName}]");
		migrationBuilder.Sql($"ALTER TABLE [{tableName}] DROP CONSTRAINT [DF_{tableName}_FsId]");
		migrationBuilder.Sql($"ALTER TABLE [{tableName}] DROP CONSTRAINT [UQ_{tableName}_FsId]");
		migrationBuilder.Sql($"ALTER TABLE [{tableName}] DROP COLUMN [FsId]");
	}
}
6. 初期マイグレーションクラスの Up メソッドで最後にヘルパーメソッドを呼びます。
FileStreamHelper.UpTable(migrationBuilder, nameof(FooTable), nameof(FooTable.FileDataColumn));
7. 初期マイグレーションクラスの Down メソッドで最初にヘルパーメソッドを呼びます。
FileStreamHelper.DownTable(migrationBuilder, nameof(FooTable), nameof(FooTable.FileDataColumn));
これで byte 配列を介した Transact-SQL による FILESTREAM アクセス が実現できます。

ファイルサイズに対してよりスケーラブルな 「ファイル システム ストリーミング」(Win32 API)方式 でアクセスする場合は、DbContext クラスの OnModelCreating メソッドでファイルデータ列を Ignore したうえで、取得、保存ロジックを別途実装する必要があります。
Uri 型のプロパティを定義すると、XAML デザイナでリストからページを選択できるようになります。
ページ文字列は既定のコンバーター UriTypeConverter によって Uri に変換されますが、
絶対パスに変換してくれるわけではありませんので、
NavigationWindow や NavigationService の Navigate メソッドに渡しても検索することができません。

Navigate には「パッケージの URI」が必要です。
NavigationWindow クラスは IUriContext の BaseUri プロパティを明示的に実装しており、
これを利用することで(NavigationWindow のパスからの)ページの相対 Uri を「パッケージの URI」に変換することができます。
Uri baseUri = ((IUriContext)navigationWindow).BaseUri;
Uri packUri = new Uri(baseUri, foo.PageRelativeUri/*← XAMLで設定したプロパティ*/);
navigationWindow.Navigate(packUri);
Windowsフォームの Dock は非常に便利ですが、
コントロールを追加していくと重なってしまったり(同じ階層のコントロールなのに)、位置関係がうまく制御できなくなったりします。

貼り付ける順序が関係しているのかと、いったん切り取って貼り付け直したりしてもダメです。
(貼り付け直すとイベントハンドラとの関連付けが解除されてしまうので注意が必要です。)

Designer ファイルを直接編集して、this.Controls.SetChildIndex の実行順序を確定したい位置の順に変えると、希望どおりの位置関係にすることができます。
(例えば、Fill の上に Bottom が重なってしまった場合、Bottom の SetChildIndex を Fill より先に実行する。)

SetChildIndex は、[最前面へ移動][最背面へ移動]で制御できるようですが、
現在のZオーダーがどうなっているのか、デザイナ上ではわからないので、Designer ソースを直接編集した方が早いと思います。
引数を強制したいので引数なしコンストラクタは使用不可にしたいことがありますが、フォームをデザイナ表示するときに基底クラスのインスタンスが生成されますので、基底クラスに引数なしのコンストラクタがないとデザイナ表示できません。

そのような場合、デザイナ用に引数なしのコンストラクタを private で定義しましょう。
private FormBase()
{
	InitializeComponent();
}
  
protected FormBase( int param )
	: this() // 引数なしのコンストラクタを呼び出して、InitializeComponent を実行する。
{
	this.param_ = param;
}
【前提】
Visual Studio .NET で開発する Windows フォームアプリケーション。

【課題】
Windows フォームの基底クラスは、
Visual Studio のデザイナで派生クラス(フォーム)を編集する際にインスタンス生成されるため、
抽象クラスにすることができません。
フォームにメソッドの実装を強制したいとき、抽象メソッドを定義できないのは困ります。
基底クラスに仮想メソッドを定義して、その中で NotImplementedException を throw する、という代替手法もありますが、
実行しないと検出されないため、実装を強制する手段としては弱いと言わざるを得ません。

【解決策】
抽象メソッドを定義できない代わりに、デリゲートで多態性を実現します。
派生クラス(フォーム)に定義したメソッドを
デリゲートインスタンスとして基底クラスのコンストラクタが受け取ることで、
間接的に実装を強制することができます。
デザイナでのインスタンス生成に必要な基底クラスの引数なしコンストラクタは private で定義します。

【実装例】
// 抽象的基底クラス
partial class FormBase : System.Windows.Forms.Form
{
	// デリゲートインスタンス(派生クラスに静的メソッドとして定義する例)
	private Func<int, int> strategyForStatic_;
	
	// デリゲートインスタンス(派生クラスにインスタンスメソッドとして定義する例)
	private Action<FormBase> strategyForInstance_;
	
	// privateフィールド
	private readonly int intValue_ = 1;
	
	// コンストラクタ(デザイナ用)
	private FormBase()
	{
		InitializeComponent();
	}
	
	// コンストラクタ(派生クラス用)
	protected FormBase(
		// デリゲートインスタンスを受け取る
		Func<int, int> strategyForStatic, // 静的メソッド
		Action<FormBase> strategyForInstance // インスタンスメソッド
	) : this()
	{
		this.strategyForStatic_ = strategyForStatic;
		this.strategyForInstance_ = strategyForInstance;
	}
	
	// 処理メソッド
	public void DoSomething()
	{
		// 派生クラスから受け取った静的メソッドを呼び出す。
		if( this.strategyForStatic_ != null ) {
			int i = this.strategyForStatic_.Invoke(this.intValue_); // privateフィールドを渡す。
			Console.WriteLine(i);
		}
		
		// 派生クラスから受け取ったインスタンスメソッドを呼び出す。
		if( this.strategyForInstance_ != null ) {
			this.strategyForInstance_.Invoke(this);
		}
	}
}
// 派生クラス(実装フォーム)
partial class DerivedForm : FormBase
{
	// コンストラクタ
	public DerivedForm()
	 : base( // デリゲートインスタンスを渡す。
		   DoByStatic, // 静的メソッド
		   (frm) => { ((DerivedForm)frm).DoByInstance(); } // インスタンスメソッド
		)
	{
		InitializeComponent();
	}

	// デリゲート用静的メソッド
	private static int DoByStatic( int i ) // 基底クラスからprivateフィールドを受け取る。
	{
		return ++i;
	}
	
	// デリゲート用インスタンスメソッド
	private void DoByInstance()
	{
		Console.WriteLine(this.ToString());
	}
}
【バリエーション】
基底クラスフィールドへのアクセスを、
デリゲートメソッドの引数として限定的に派生クラスへ許可することもできます。
(上の実装例では「intValue_」)

【結論】
この実装パターンを使用することで、抽象メソッドをオーバーライドするのと似た感覚で、
派生クラス(フォーム)にメソッドを定義することができます。
ただし、これは Visual Studio デザイナの制限下で限られた目的を達成するための代替手段です。
抽象クラスにできるなら素直に抽象メソッドを定義した方がいいですし、
Windows フォームの場合も、必要性をよく検討してから利用した方がよいでしょう。
Form クラスは IDisposable を実装しており、使い終わったら Dispose することが推奨されています。
Form を一度 Dispose すると、その後同じインスタンスで表示させることはできなくなります。
(Dispose した Form を Show すると、ObjectDisposedException が発生します。)

フォームを閉じたとき、暗黙的に Dispose されるのか、されないのか。
これは、フォームがモーダルかどうか、どのように閉じられたかによって変わってきます。

以下、間違えがちな点をクイズにしてみました。
いずれも単独の Form を Show() もしくは ShowDialog() したことを前提としています。
(1) モードレスフォームを×ボタンで閉じると、  
(2) モードレスフォームを Close() すると、  
(3) モードレスフォームを Hide() しても Dispose はされないが、  
(4) モードレスフォームで DialogResult を設定すると、  
(5) モーダルフォームを×ボタンで閉じると、  
(6) モーダルフォームをボタンのクリックイベントから自分自身で Close() すると、  
(7) モーダルフォームが×ボタンで閉じられた後、呼び出し元コードから Close() すると、  
(8) モーダルフォームを Hide() しても Dispose はされないが、  
(9) モーダルフォームを Hide() しても Dispose はされないが、  
(10) モーダルフォームで DialogResult を設定するとフォームが閉じられるが、  
閉じ方によるイベント発生、Dispose の有無を表にまとめると以下のようになります。
閉じ方 モードレス モーダル
FormClosing FormClosed Dispose FormClosing FormClosed Dispose
×ボタン 発生する 発生する される 発生する 発生する ×
Close フォーム(自分自身)内のイベント 発生する 発生する される 発生する 発生する ×
起動元の Show(Dialog) に続くコード 発生する 発生する される される
Hide × × × 発生する × ×
Visible = false
DialogResult 設定 ―(閉じられない) 発生する 発生する ×

ASP.NET には、知っておくと便利な静的ユーティリティメソッド/プロパティがたくさんあります。
そのうち、比較的知られていないものをいくつかご紹介します。

  ○サーバー/セッション/リクエスト/レスポンス
   ・HttpContext.Current.Server プロパティ
   ・HttpContext.Current.Session プロパティ
   ・HttpContext.Current.Request プロパティ
   ・HttpContext.Current.Response プロパティ
   Page.Session や Page.Request を引数やコンストラクタで受け取らなくてもアクセスできます。
   
  ○物理パス
   ・HostingEnvironment.MapPath メソッド
   仮想パスから物理パスを取得するには Server.MapPath メソッドを使用することが多いと思いますが、
   Server オブジェクトがなくても取得できます。
   
  ○絶対パス/アプリケーション相対パス
   ・VirtualPathUtility.ToAbsolute メソッド
   ・VirtualPathUtility.ToAppRelative メソッド
   VirtualPathUtility.ToAbsolute は、Control オブジェクトにアクセスできないとき、
   ResolveUrl メソッドに代わるものとして使用できます。
   
  ○クエリ文字列解析
   ・HttpUtility.ParseQueryString メソッド
   クエリ文字列の解析に使用する場合、エンコードされたキーや値は自動でデコードされます。
   解析には既定で UTF-8 が使用されます。
   UTF-8 以外の、たとえば Shift_JIS でエンコードされたクエリ文字列を解析する場合は、
    HttpUtility.ParseQueryString(query, Encoding.GetEncoding("Shift_JIS"))
   のようにエンコーディングを明示指定します。
  ○JavaScript 文字列エンコード
   ・HttpUtility.JavaScriptStringEncode メソッド
   .NET 4 から使えるようになりました。
   
  ○色
   ・ColorTranslator.FromHtml メソッド
   ・ColorTranslator.ToHtml メソッド
   ColorTranslator.FromHtml("#99CCFF") や ColorTranslator.FromHtml("Blue") のように
   文字列から Color 構造体を取得したり、
   ColorTranslator.ToHtml(Color.Red) のように Color 構造体から HTML で使用できる文字列を取得したりできます。
Response.Redirect で、URL のスペルを間違えて 404 エラー。(インテリセンスが効きません)
ディレクトリ変更の反映もれで 404 エラー。(コンパイルエラーになりません)
たまにありますね。
無駄になる時間はわずかですが、こうしたつまらないミスに集中力を削がれるのは避けたいものです。

そこで、ページクラスの型から URL を生成してリダイレクトする共通メソッドを作ってみます。
using System;
using System.Collections.Specialized;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.UI;

// 文頭のアセンブリ名を表す正規表現
private static readonly Regex assemblyNameRegex_ = new Regex("^" + Regex.Escape(Assembly.GetExecutingAssembly().GetName().Name));

public static void ResponseRedirect<T>() where T: Page
{
	ResponseRedirect<T>(null);
}

public static void ResponseRedirect<T>( NameValueCollection parameters ) where T: Page
{
	ResponseRedirect(typeof(T), parameters);
}

public static void ResponseRedirect( Type pageType, NameValueCollection parameters )
{
	// ページクラス型の完全修飾名から先頭のアセンブリ名部分を除き、仮想パスの形式にする。
	// 《例》SampleWeb.Account.Login → ~/Account/Login.aspx
	string path = String.Format("~{0}.aspx", assemblyNameRegex_.Replace(pageType.FullName, "").Replace(".", "/"));
	
	string url = BuildUrl(path, parameters);
	
	HttpContext.Current.Response.Redirect(url, false);
}

public static string BuildUrl( string path, NameValueCollection parameters )
{
	if( parameters == null || parameters.Count == 0 ) return path;
	
	List<string> queries = new List<string>();
	foreach( string key in parameters.Keys )
	{
		foreach( string value in parameters.GetValues(key) )
		{
			queries.Add( String.Format("{0}={1}", HttpUtility.UrlEncode(key), HttpUtility.UrlEncode(value)) );
		}
	}
	
	return String.Format("{0}?{1}", path, String.Join("&", queries.ToArray()));
}
こんな風に使います。
// リダイレクト
ResponseRedirect<Account.Login>();

// パラメータ付きでリダイレクト
NameValueCollection parameters = new NameValueCollection();
parameters.Add("param", "あいうえお");
ResponseRedirect<Account.Login>(parameters);

※この ResponseRedirect メソッドをそのまま使用するには、以下の2つの条件が前提となります。
 ・アセンブリ名と既定の名前空間が一致している。
 ・aspx のパスとコードビハインドの(名前空間を含む)クラス名の同期がとれている。
  (既定でディレクトリごとに名前空間が付与されない VB.NET には向かない方法です。)
1. IIS を構成
 コントロールパネル
  →プログラムと機能
   →Windowsの機能の有効化または無効化
    →Internet Information Service
     →Web管理ツール
      →IIS6と互換性のある管理をすべてチェック
     →World Wide Web サービス
      →アプリケーション開発機能
       →ASP.NET にチェック

2. .NET Framework v1.1 をインストール

3. .NET Framework v1.1 日本語 Language Pack をインストール

4. .NET Framework v1.1 SP1 をインストール
  →Windows 再起動(しないと正しく適用されないので注意)

5. ISAPI および CGI の許可
 管理ツールから [インターネット インフォメーション サービス (IIS) マネージャ] を開く。
 ホームから [ISAPIおよびCGIの制限] を開き、「ASP.NET v1.1.4322」をダブルクリックして「拡張パスの実行を許可する」をチェックする。

6. ASP.NET 1.1 アプリケーションプールの作成
 IISマネージャの [アプリケーションプール](コンピュータの下の階層)にv1.1のものがない場合、「.NET Framework 1.1.4322」を指定した「ASP.NET 1.1」を追加する。

【以下、アプリケーションごとに設定が必要】

7. WEB アプリケーションをインストール
 Setup.Exe を起動する。
 ※msi の単独起動だと管理者として実行されず、インストールに失敗する。
  msiexec /i .msiファイル名 というバッチを作って管理者として実行してもよい。

8. WEBアプリケーションをASP.NET 1.1 クラシックモードに移行
 IISマネージャで[Webサイト]-[Default Web Site]のアプリケーションホームを右クリックし、[詳細設定]でアプリケーションプールを「ASP.NET 1.1」に変更。
ASP.NET アプリケーションを IIS でホストする際、URL Rewrite モジュールを活用することで、URL 正規化や https への自動リダイレクト、アクセス元 IP アドレスの制御などが可能となります。

ASP.NET Core では、Rewrite ミドルウェア を使用することによって、アプリケーションレベルでの URL 書き換えを行うことができます。

ルールの定義はXMLファイルに記述します。
以下は Azure Web Apps で URL 正規化を行う例です。

[IISUrlRewrite.xml]
出力ディレクトリにコピー:新しい場合はコピーする
<rewrite>
  <rules>
    <rule name="Enforce canonical hostname" stopProcessing="true">
      <match url="(.*)" />
      <conditions logicalGrouping="MatchAny">
        <!-- www サブドメイン -->
        <add input="{HTTP_HOST}" pattern="^www\.fullofnull\.jp$" />
        <!-- Azure WebApps DNS名 -->
        <add input="{HTTP_HOST}" pattern="^fullofnull\.azurewebsites\.net$" />
      </conditions>
      <action type="Redirect" url="http://fullofnull.jp/{R:1}" redirectType="Permanent" />
    </rule>
  </rules>
</rewrite>
Startup クラスの Configure メソッドから呼び出します。
UseMvc より前に呼ばないと適用されないので注意が必要です。
var options = new RewriteOptions()
    .AddIISUrlRewrite(env.ContentRootFileProvider, "IISUrlRewrite.xml");
app.UseRewriter(options);
ASP.NET Core から Entity Framework Core を使用する場合、外出しにする接続文字列は appsettings.json に定義します。
  "ConnectionStrings": {
    "FooConnection": "Server=.\\InstanceName;Database=DatabaseName;Trusted_Connection=True;"
  }
DbContext は Startup クラスの ConfigureServices メソッドで DI コンテナに登録します。
以下は SQL Server に接続するコンテキストを登録する例です。
services.AddDbContext<FooContext>(o => o.UseSqlServer(Configuration.GetConnectionString("FooConnection")));
登録された DbContext は Controller のコンストラクタ引数を通して取得できます。
Entity Framework Core で add されたマイグレーションは以下のコマンドでデータベースに手動適用できます。

[パッケージマネージャーコンソール]
Update-Database -Context FooContext
[CLI コマンド]
dotnet ef database update --context FooContext
ASP.NET Core でアプリケーション起動時にマイグレーションを自動適用させるためには、Program.Main メソッドに次のように記述します。
public static void Main(string[] args)
{
	var host = BuildWebHost(args); // ASP.NET Core 2.0 の場合

	using (var scope = host.Services.CreateScope())
	{
		var services = scope.ServiceProvider;
		try
		{
			var context = services.GetRequiredService<IssueTrackerContext>();

			// 自動マイグレーション適用
			context.Database.Migrate();

			// 初期データ生成
			// ※Data フォルダ内にカスタムクラスを作成してデータ生成コードを記述しておく。
			DbInitializer.Initialize(context);
		}
		catch (Exception ex)
		{
			var logger = services.GetRequiredService<ILogger<Program>>();
			logger.LogError(ex, "データベース初期構成中にエラーが発生しました。");
		}
	}

	host.Run();
}
※Startup.Configure に記述すると Add-Migration で実行されてしまいます。(ASP.NET Core 2.0 で確認)
SQLServerへのデータインポートにはいくつか方法があります。
それぞれの特徴をまとめてみました。

▼SSMA(SQL Server Migration Assistant)
・速い。
・定義も移行できる。
・「for Access」ではアップサイジングウィザードのバグも修正されている。
・APIやコマンドラインツールが用意されていない。

▼BULK INSERT
・他 DBMS から直接読めない(テキストファイルを介す)。
・CSV の文字列引用符も値に含めてロードしてしまう(引用符を外すには FORMATFILE の作成が必要)。

▼BCP
(BULK INSERT とほぼ同じ)

▼ODBC 経由の INSERT INTO
・遅い(例:200万行で15分)。
・以下のような形式で Jet.OLEDB ドライバなどから使用できる。
  INSERT INTO
    [ODBC;DRIVER={SQL Server};SERVER=;DATABASE=;UID=;PWD=;].TableName
 :

▼DTS
・速い(例:200万行で1分半)。
・テーブル定義は移行できるが、主キー、インデックスなど制約は移行できない。
・.NET から扱える API が提供されているが、パッケージ作成に列定義が必要で、かなり手間がかかる。
・実行端末に SQLServer がインストールされている必要がある。

▼SqlBulkCopy クラス(System.Data.SqlClient)
・速い(例:200万行で2分半)。
・他 DBMS のクエリ結果を、テキストファイルを介さずにインポートできる。(DataReader 使用)
・DataTable や DataRow[] の中身もインポート可能。
・Excel や CSV から OleDbConnection 経由でインポートする場合、データ型の自動判別に注意が必要。
MDB の CSVエクスポートは、TransferText より [Text;DATABASE=...] の外部参照を使用した方が断然高速です。
SELECT
	[MdbQuery].*
INTO
	[Text;DATABASE=C:;HDR=YES;FMT=Delimited;CharacterSet=OEM;].[Test.csv]
FROM
	(SELECT * FROM MdbTable WHERE Id > 10) AS [MdbQuery]
《例》100万行のエクスポート
  TransferText: 5分
  TextDriver  : 26秒
TextDriver を使うとテキストデータを加工して SQL で Oracle などの DBMS にインポートすることができます。
(注:高速ではありません)
INSERT INTO
	[挿入先テーブル]
(
	[列1],
	[列2],
	[列3]
)
IN
	'' [ODBC;Driver=Microsoft ODBC for Oracle;SERVER=TNS名;UID=ユーザー名;PWD=パスワード]
SELECT DISTINCT
	[Csv列1],
	[Csv列2],
	[Csv列3]
FROM
	元ファイル.csv
WHERE
	[Csv列1] IS NOT NULL // ← CSV(テキスト)ファイルが改行で終わっていたりする場合の対策
※接続文字列で「BufferSize=」を指定すると、一度にメモリに抱える行数を制御できます。
SQLServer からはリンクサーバー機能で 他の DBMS にアクセスできますが、
ODBCドライバを使って、異なる DBMS 間で JOIN させることもできます。
(大量のデータを扱う場合、パフォーマンスには注意が必要です。)
SELECT
	MSSQL.*,
	MDB.MdbColumn
FROM
(
	SELECT
	CategoryID,
	MdbColumn
FROM
	[MDBテーブル名]
) AS MDB
INNER JOIN
(
	SELECT
		*
	FROM
		[MSSQLテーブル名]
	IN
		'' [ODBC;DRIVER=SQL Server;SERVER=サーバー;DATABASE=データベース;UID=ユーザー名;PWD=パスワード;]
) AS MSSQL
ON
	MDB.CategoryID = MSSQL.CategoryID
SQL Server 製品版では、定期的なバックアップをメンテナンスプランで構成することが多いと思います。

エージェントサービスのアカウントに共有フォルダへのアクセス権限があれば、バックアップの出力先に共有フォルダを指定することも可能ですが、
ローカルにバックアップを出力したうえでリモートにもコピーして多重化したい、ということもあるでしょう。
また、データベースと同期をとるべきリソースファイル群も、同じタイミングでリモートにバックアップできれば便利です。

ここでは、ローカルに出力したデータベースバックアップとリソースファイル群を共有フォルダにコピーする方法をご紹介します。
バックアップのサイクルは日次で、データベースバックアップは一週間分の世代を保持するものとします。
リソースファイル群は差分のみ適用して同期をとります。

1. Management Studio を起動してデータベースに接続します。

2. メンテナンスプランを作成します。
        
3. サブプランを追加してスケジュールを設定します。
        
4. [ツールボックス] から「データベースのバックアップ タスク」をドラッグして必要なプロパティを設定します。
        
5. [SQL Server エージェント] から、データベースバックアップのコピージョブを作成します。

 種類:PowerShell

Copy-Item -Force -Path "C:\Backup\SQLServer\EveryDay.bak" -Destination ("Microsoft.PowerShell.Core\FileSystem::\\remote-pc\Backup\SQLServer\Everyday_{0}.bak" -f (get-date).DayOfWeek)
※「(get-date).DayOfWeek」で「Sunday」など曜日文字列を付加しています。
※「Microsoft.PowerShell.Core\FileSystem::」をつけないとコピーされないようです(Management Studio 11.0.3000.0 で確認)。
 ジョブ履歴に成功と記録はされていますが、詳細を確認すると PowerShell で次のエラーが発生していることがわかります。
 「PowerShell によって返されたエラー情報: 'コピー元パスとコピー先パスが同じプロバイダーを解決しませんでした。 」      

6. [SQL Server エージェント] から、リソースファイル群の同期ジョブを作成します。

 種類:PowerShell

robocopy "C:\Backup\Resources" "\\remote-pc\Backup\Everyday\Resources" /E /DCOPY:T /MIR
※robocopy はコピーに成功したときの戻り値が 0 でないため、[種類] に「オペレーティング システム(CmdExec)」を指定すると既定で失敗扱いにされてしまいます。

7. サブプランのデザインに戻ります。
      
8. [ツールボックス] から「SQL Server エージェント ジョブの実行タスク」をドラッグして矢印で接続し、 [編集] から「5」のジョブを選択します。
      
9. [ツールボックス] から「SQL Server エージェント ジョブの実行タスク」をドラッグして矢印で接続し、 [編集] から「6」のジョブを選択します。
      
10. 作成したメンテナンスプランは [Integration Services] に接続してエクスポートできます。
  
   [格納済のパッケージ]
     [MSDB]
       [Maintenance Plans] 
      
ADODB.Stream の WriteText メソッドを使用することにより、文字列の連結を高速に行うことができます。
(例:20文字×10,000行の連結が 40秒 → 0.4秒 と100倍高速化)

この方法を使用した以下の StringBuilder クラスを組み込むと、
 sLines = sLines & "Line" & vbCrLf
に相当する処理を
 sb.AppendLine("Line")
のように記述できるようになります。
Option Explicit


'▼列挙型

'改行文字
Public Enum LineSeparatorsEnum
	adCR = 13
	adCRLF = -1
	adLF = 10
End Enum


'▼メンバ変数

'ストリームオブジェクト
Private mStream As Object 'ADODB.Stream


'▼プロパティ

'改行文字 ※デフォルトはvbCrLf
Public Property Get LineSeparator() As LineSeparatorsEnum
	LineSeparator = mStream.LineSeparator
End Property
Public Property Let LineSeparator(ByVal e As LineSeparatorsEnum)
	mStream.LineSeparator = e
End Property

'文字列の長さ
Public Property Get Length() As Long
	If mStream.Size <= 0 Then
		Length = mStream.Size
	Else
		Length = (mStream.Size / 2) - Len(vbNullChar) 'Len(ToString())だと遅い。
	End If
End Property


'▼メソッド

'コンストラクタ
Private Sub Class_Initialize()
	
	Set mStream = CreateObject("ADODB.Stream")
	mStream.Type = 2 'adTypeText
	LineSeparator = adCRLF
	Call mStream.Open
	
End Sub


'文字列を追加する。
Public Function Append(ByVal s As String) As StringBuilder
	
	Call mStream.WriteText(s, 0) 'adWriteChar
	
	Set Append = Me
	
End Function


'改行付で文字列を追加する。
Public Function AppendLine(Optional ByVal s As String = "") As StringBuilder
	
	Call mStream.WriteText(s, 1) 'adWriteLine
	
	Set AppendLine = Me
	
End Function


'文字列化する。
Public Function ToString() As String
	
	mStream.Position = 0
	
	ToString = mStream.ReadText()
	
	mStream.Position = mStream.Size
	
End Function


'デストラクタ
Private Sub Class_Terminate()
	
	Call mStream.Close
	
End Sub
VB6 でも(簡易的・擬似的ではありますが)ユニットテストを実装することができます。

 1. テスト用の標準モジュールを作成します。
 2. テスト用の Public メソッドを定義します。
 3. テスト対象の処理を記述します。
 4. Debug.Assert で処理結果を検証します。
 5. イミディエイトウィンドウからテストメソッドを実行します。
 (テストメソッド呼び出しを集めたメソッドを作成しておくと、一括実行できます。)

モッククラスを作ることも可能です。

VB6 には Implements という、インターフェイスの実装をするためのステートメントが用意されています。
.NET や Java の「インターフェイス」とは以下のような点で異なる、簡易的なゆるい仕組みです。
 ・インターフェイスとして指定されるのはただのクラスである。
 ・実装メソッドは {InterfaceClass}_{Method} という、イベントハンドラのような形式の名称で定義する。
 ・実装メソッドは既定では Private のため、実装クラス型の変数から実装メソッドに直接アクセスすることはできない。
  (Public に変えたり、Public な転送メンバを定義してアクセスすることはできる。)

この Implements ステートメントのゆるい点をポジティブに活用すると、
  1. インターフェイスとして利用するクラスを基底クラスと位置づけ、共通ロジックを記述する。
  2. 実装クラスのメンバ変数にインターフェイスとして利用するクラスのインスタンスを保持する。
  3. 実装メソッドから、必要に応じて「2.」の委譲インスタンスのメソッドを呼ぶ。
という方法で擬似的な継承を実現することができます。

以下は、この方法で作成したモッククラスを利用したユニットテストの例です。
(このページの「文字列連結の超高速化」でご紹介した StringBuilder クラスを使用します。)

まず StringBuilderTest という標準モジュールを作成して StringBuilder のテストを記述します。
'StringBuilderTest.bas

Option Explicit

'Length_SingleLine
Public Sub TestStringBuilder_Length_SingleLine()
    
    With New StringBuilder
        Debug.Assert 0 = .Length
        
        Call .Append("")
        Debug.Assert 0 = .Length
        
        Call .Append("あい")
        Debug.Assert 2 = .Length
    End With
    
End Sub

'Length_MultiLine
Public Sub TestStringBuilder_Length_MultiLine()
    
    With New StringBuilder
        .LineSeparator = adLF
        
        Call .AppendLine("Line")
        Debug.Assert 5 = .Length
    End With
    
End Sub

'ToString
Public Sub TestStringBuilder_ToString()
    
    With New StringBuilder
        .LineSeparator = adLF
        
        Call .Append("Code")
        Debug.Assert "Code" = .ToString()
        
        Call .AppendLine("One")
        Debug.Assert "CodeOne" & vbLf = .ToString()
    End With
    
End Sub
テストメソッドはイミディエイトウィンドウから実行します。
成功すればそのままカーソルが下の行に移動します。
検証に失敗すると、失敗した位置で実行が止まります。

次にモッククラス MockStringBuilder を作成します。
(LineSeparator プロパティでしているように、base フィールドを使用して
 Moq の CallBase 的にオリジナルの処理を実行することもできます。)
'MockStringBuilder.cls

Option Explicit

'インターフェイス
' StringBuilder 型で扱えるよう、同じインターフェイスを StringBuilder_{Method} 形式で実装する。
Implements StringBuilder

'委譲インスタンス
' 擬似的な継承を実現するため、インスタンスを保持する。
Private base As New StringBuilder

'モック用のフィールド
Private mAppendCalled As Long
Private mAppendLineCalled As Long
Private mToStringReturn As String

'Append が呼ばれた回数
Public Property Get AppendCalled() As Long
    AppendCalled = mAppendCalled
End Property
Public Property Let AppendCalled(ByVal n As Long)
    mAppendCalled = n
End Property

'AppendLine が呼ばれた回数
Public Property Get AppendLineCalled() As Long
    AppendCalled = mAppendLineCalled
End Property
Public Property Let AppendLineCalled(ByVal n As Long)
    mAppendLineCalled = n
End Property

'ToString で返す値
Public Property Get ToStringReturn() As String
    ToStringReturn = mToStringReturn
End Property
Public Property Let ToStringReturn(ByVal s As String)
    mToStringReturn = s
End Property

'改行文字
Private Property Let StringBuilder_LineSeparator(ByVal e As LineSeparatorsEnum)
    base.LineSeparator = e
End Property
Private Property Get StringBuilder_LineSeparator() As LineSeparatorsEnum
    StringBuilder_LineSeparator = base.LineSeparator
End Property

'文字列の長さ
Private Property Get StringBuilder_Length() As Long
    Debug.Assert False
End Property

'文字列を追加する。
Private Function StringBuilder_Append(ByVal s As String) As StringBuilder
    
    '呼ばれた回数をカウントする。
    mAppendCalled = mAppendCalled + 1
    
End Function

'改行付で文字列を追加する。
Private Function StringBuilder_AppendLine(Optional ByVal s As String = "") As StringBuilder
    
    '呼ばれた回数をカウントする。
    mAppendLineCalled = mAppendLineCalled + 1
    
End Function

'文字列化する。
Private Function StringBuilder_ToString() As String
    
    'モック用の値を返す。
    StringBuilder_ToString = mToStringReturn
    
End Function
StringBuilder を使用するクラス Sample があるとします。
'Sample.cls

Option Explicit

Private mBuilder As StringBuilder
Public Property Get Builder() As StringBuilder
    Builder = mBuilder
End Property
Public Property Set Builder(ByVal o As StringBuilder)
    Set mBuilder = o
End Property

Public Sub Class_Initialize()
    
    Set mBuilder = New StringBuilder
    
End Sub

Public Function GetText() As String
    
    Call mBuilder.Append("Text")
    GetText = mBuilder.ToString()
    
End Function
この Sample クラスをテストするのに MockStringBuilder を使用してみます。
'SampleTest.bas

Option Explicit

'GetText
Public Sub TestSample_GetText()
    
    Dim oMockBuilder As New MockStringBuilder
    oMockBuilder.ToStringReturn = "Test"
    
    With New Sample
        Set .Builder = oMockBuilder
        
        Dim sActualText As String
        sActualText = .GetText()
        
        Debug.Assert 1 = oMockBuilder.AppendCalled
        Debug.Assert 0 = oMockBuilder.AppendLineCalled
        Debug.Assert "Test" = sActualText
    End With
    
End Sub
Recordset をクライアントカーソルで取得して、
rs("列1").Properties("OPTIMIZE") = True
を実行するとメモリ上にインデックスが作成され、Filter 操作が驚異的に(ケースによっては数十倍)速くなります。
インデックス作成にかかる時間はわずかです。

※メモリ上のインデックスは、Sort プロパティに列名をセットすることでも作成されます。