Enum ではなく Class を使う
Enum を使うと switch ... case ... することになる。
たとえば、プログラム言語を Enum で定義して、その名前を表示する例。
using System; namespace UseClassInsteadOfEnum { public enum ProgrammingLanguageEnum { CSharp, Java, } public class ByEnum { public static void PrintName(ProgrammingLanguageEnum progLang) { switch (progLang) { case ProgrammingLanguageEnum.CSharp: Console.WriteLine("C#"); break; case ProgrammingLanguageEnum.Java: Console.WriteLine("Java"); break; default: throw new ArgumentException("progLang"); } } } }
Enum だと、
- なにかするには switch ... case ... を書かないと、、、
- 一応 default も書いておかないと心配だし、、、
- 将来 Enum のメンバを変更したら、全部調べて修正しないと、、、
と、悩むことになる。
クラスにすると、スッキリする。
using System; namespace UseClassInsteadOfEnum { public class ProgrammingLanguageClass { // 各項目を表わすインスタンスは static にする。 private static ProgrammingLanguageClass _cSharp = new ProgrammingLanguageClass("C#"); public static ProgrammingLanguageClass CSharp { get { return _cSharp; } } private static ProgrammingLanguageClass _java = new ProgrammingLanguageClass("Java"); public static ProgrammingLanguageClass Java { get { return _java; } } private String _name; // コンストラクタは private にして、クラス外からインスタンスが作れないようにする。 private ProgrammingLanguageClass(String name) { _name = name; } public String Name { get { return _name; } } } public class ByClass { public static void PrintName(ProgrammingLanguageClass progLang) { Console.WriteLine(progLang.Name); } } }
使う側からは、同じように見える。
namespace UseClassInsteadOfEnum { class Program { static void Main(string[] args) { ByEnum.PrintName(ProgrammingLanguageEnum.CSharp); ByClass.PrintName(ProgrammingLanguageClass.CSharp); } } }
プログラムをオブジェクト指向にするには
プログラムをオブジェクト指向にするには、
- そのプログラムがなにをするか、に加えて、
- それをどこにやらせるか、
が重要になる。
気を付けるのは、他のクラスのプロパティを使って、いろいろ計算しているところ。次の例では、適用期間 (ApplicableTerm) クラスを使うクラスが、ApplicableTerm の Start と End プロパティから期間内かどうかを求めている。
using System; namespace ObjectOrientedBadSample { public class ApplicableTerm { private TimeSpan _start; private TimeSpan _end; public TimeSpan Start { get { return _start; } } public TimeSpan End { get { return _end; } } } public class ApplicableTermUser { public void BadUser(ApplicableTerm term) { TimeSpan someTimePoint = new TimeSpan(); // ある時点 if (term.Start <= someTimePoint && someTimePoint <= term.End) // ======================================================== { // 適用期間内 } } } }
他のクラスのプロパティを使って自分で計算するのではなく、そのプロパティを提供するクラスにやってもらう。
using System; namespace ObjectOrientedBetterSample { public class ApplicableTerm { private TimeSpan _start; private TimeSpan _end; public bool IsIncluded(TimeSpan timePoint) { return _start <= timePoint && timePoint <= _end; } } public class ApplicableTermUser { public void GoodUser(ApplicableTerm term) { TimeSpan someTimePoint = new TimeSpan(); // ある時点 if (term.IsIncluded(someTimePoint)) // ============================== { // 適用期間内 } } } }
知識レベル-操作レベルを使うとき(1)
アナリシスパターンの知識レベル-操作レベルを使うときとして、
- プログラムの再コンパイルなしで、
- なにかの種類を増減したい。
場合がある。
たとえば、測定の種類として身長や体重などがあるとする。これらがプログラムのコンパイル時点で決定できるならば、以下のように enum で表現できる。
namespace KnowledgeOperation1 { public enum MeasurementTypeEnum { Height, Weight, // . . . . . } public class WrittenInSourceCode { MeasurementTypeEnum _measType; } }
測定の種類が増減し、プログラムを再コンパイルせずに対応するには、
- 測定の種類をクラスにして、
- そのインスタンスを生成・破棄する
ようにしておけばよい。
namespace KnowledgeOperation1 { // new MeasurementTypeClass("Height"); // new MeasurementTypeClass("Weight"); // . . . . . public class MeasurementTypeClass { public MeasurementTypeClass(string name) { // } } public class UsingReference { MeasurementTypeClass _measType; } }
参考: アナリシスパターンを読もう
Windbg で sosex を使ってマネージコードのソースレベルでブレークポイント設定
Windbg でマネージコードをデバッグするとき、sosex を使えば、ソースレベルでブレークポイントを設定できる。
- '.load sosex.dll' で sosex をロード。
- '!mbp ソースファイル名 行番号' でブレークポイント設定。
- 'g' で実行開始。
- ブレークポイントにヒットした。
- '.loadby sos.dll clr' で sos をロード (フレームワークが 3.5 までは 'clr' を 'mscorwks' に変更する、参考: Unable to load SOS in WinDbg)
- '!ClrStack' でマネージスタックを表示。
- 指定の位置でブレークしている!
Visual Studio のインクリメンタルサーチ
Visual Studio のインクリメンタルサーチを使えば、1文字打つごとにカーソルが移動し検索できる。
- Ctrl + I でインクリメンタルサーチ開始。マウスカーソルが双眼鏡の形に変わる。
- サーチする文字を入力すると、その文字へカーソルが移動する。下の例では 'c' を入力。
- 次の文字を入力すると、さらにカーソルが移動する。例では 'a' を入力し 'ca' へ移動。
- サーチ中に Ctrl + I を入力すると、次のサーチ文字列へカーソルが移動する。例では次の 'ca' へ移動。
- ESC を押すと、インクリメンタルサーチ終了。