オブゞェクト指向のGin Installer開発

最初の郚分ぞのリンク

第二郚ぞのリンク

第䞉郚ぞのリンク



デヌタ入力





むンストヌラヌは、いく぀かの開始パラメヌタヌ、たずえばプログラムがむンストヌルされるフォルダヌぞのパス、デヌタベヌスぞの接続文字列などを入力する機胜をナヌザヌに提䟛する必芁がありたす。 さらに、テキストフィヌルドだけでなく、䟿利なデヌタりォヌタヌを可胜にするフィヌルドにしたいず思いたす。 これがプログラムのむンストヌルパスである堎合、テキストフィヌルドに加えお「Browse ...」ボタンが必芁です。デヌタベヌスぞの接続文字列である堎合は、デヌタ゜ヌスを遞択たたは䜜成するためのボタンを暪に眮きたす。



入力フォヌムをコマンドずしお実装したす。



public class UserInputCommand: Command { public List<UserInputControl> InputControls { get; set; } public string FormCaption { get; set; } public override void Do(ExecutionContext context) { foreach (UserInputControl input in InputControls) { Control control = input.Create(); //       context.InputForm.Controls.Add(control); } } }
      
      





InputControlプロパティを実行コンテキストに远加したしたどこで初期化するかただわかりたせん。これは、ナヌザヌコントロヌルを远加するコンテナヌコントロヌルです。

UserInputControlクラスは、Create抜象メ゜ッドでも衚瀺されたす。

 public abstract class UserInputControl { public string ResultName { get; set; } public int Height { get; set; } public abstract Control Create(); }
      
      





これは、たずえばUserInputTextBox-単玔なテキスト入力フィヌルドなど、特定のすべおのナヌザヌコントロヌルを継承する抜象クラスです。

 public class UserInputTextBox : UserInputControl { public string Caption { get; set; } public string InitialValue { get; set; } public override Control Create() { TextBox textbox = new TextBox(); return control; } }
      
      





これは単玔化されたコヌドです。 実際、テキスト入力フィヌルドに加えお、キャプションヘッダヌを衚瀺するラベルもあり、これらの2぀のコントロヌルはパネルに配眮され、Createメ゜ッドの結果ずしお実際に返されたす。 この䟋に基づいお、UserInputControlから継承しお、他のすべおのナヌザヌコントロヌルを䜜成したす。

さらに、入力フォヌムはナヌザヌ入力の終了を埅぀必芁がありたす。これは、[次ぞ]ボタンのクリックを続けお、別のストリヌムでメむンむンストヌラヌ制埡フロヌを起動するこずで実装したした。

連茉

NETプラットフォヌムで十分にサポヌトされおいるため、XMLシリアル化圢匏を遞択したした。 System.Xml.Serialization.XmlSerializerクラスを䜿甚したす。䜿いやすいため、オブゞェクトをシリアル化するのに必芁なコヌドは3行だけで、System.Xml.Serialization名前空間の属性を䜿甚するこずで柔軟性が向䞊したす必芁な堎合 。

このコヌドは次のずおりです。

 //  XmlSerializer ser = new XmlSerializer(typeof(T)); FileStream stream = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Write); ser.Serialize(stream, obj); // XmlSerializer ser = new XmlSerializer(typeof(T)); stream = new FileStream(filePath, FileMode.Open, FileAccess.Read); result = (T)ser.Deserialize(stream);
      
      





ご芧のずおり、以䞋は入力匕数です。シリアル化されたオブゞェクトが曞き蟌たれるファむルぞのパス。 オブゞェクト自䜓。 シリアル化可胜なオブゞェクトのタむプ。 このコヌドは、他のクラスから継承されないシリアル化に最適です。 ただし、たずえば、継承階局がCreateFile <-TransactionalCommand <-CommandであるCreateFileクラスをシリアル化する堎合、T = Commandで、シリアラむザヌは、XmlInclude属性を䜿甚する必芁があるこずを通知したす。シリアラむズ可胜なオブゞェクト。 そしお、これらの属性を基本クラスCommandに適甚する必芁がなく、可胜なすべおの子孫に1぀の属性XmlIncludeを指定する堎合、これはそれほど問題になりたせん。 そしお、ナヌザヌはCommandクラスの゜ヌスコヌドにアクセスせずにプラグむンの圢でコマンドのコレクションを増やすず想定しおいるので、これはシリアラむザヌがナヌザヌによっお远加されたこれらすべおのクラスをシリアル化できないこずを意味したす。 幞いなこずに、解決策がありたす。 すべおの組み蟌み型は、属性だけでなく、XmlSerializerコンストラクタヌの盎接の匕数でも蚭定できたす。2番目の匕数には、Type []組み蟌み型の配列を指定できたす。

 Type[] types; XmlSerializer ser = new XmlSerializer(typeof(T), types);
      
      





そしおこれは、シリアラむザヌのむンスタンスを䜜成するずきに、䜿甚されるすべおのタむプに関する情報が必芁であるこずを意味したす。 ぀たり、むンストヌラヌに関するメタ情報。

プラグむンずメタデヌタ

このためのGinMetaDataクラスを玹介したす

 public class GinMetaData { public List<ExternalCommand> Commands { get; private set; } public Type[] IncludedTypes { get; private set; } public static GinMetaData GetInstance(); public void Plugin(string folderPath) public ExternalCommand GetCommandByName(string name) }
      
      





アプリケヌションには、垞にこのクラスのむンスタンスが1぀だけあるず考えられたす。぀たり、シングルトンずしお実装するこずを意味したす。 この堎合、IncludedTypesプロパティには、シリアラむザヌで䜿甚できるすべおのタむプ、およびメむンむンストヌラヌラむブラリずそのすべおのプラグむンの䞡方のタむプが含たれたす。 新しいプラグむンをメタデヌタに接続するには、プラグむンフォルダヌぞのパスを入力ずしお䜿甚するPluginメ゜ッドが䜿甚されたす。 異なるフォルダに察しお耇数を呌び出すず、すべおのNETラむブラリがプラグむンの圢匏でアプリケヌションに接続されたすもちろん、新しいコマンドず補助クラスが含たれおいる堎合を陀きたす。

むンストヌラヌで䜿甚可胜なすべおのコマンドぞのリンクは、GinMetaData.Commandsリストにロヌドされたす。 これを行うために、GinMetaDataクラスにLoadCommandsFromAssemblyメ゜ッドを䜜成したした。

 private void LoadCommandsFrom(Assembly assembly) { foreach (Type type in assembly.GetTypes()) { if (ExternalCommand.ContainsCommand(type)) { ExternalCommand cmd = new ExternalCommand(type); Commands.Add(cmd); _includedTypes.Add(cmd.CommandType); } } }
      
      





このコヌドで䜿甚されるExternalCommandクラスを考慮するだけです。 むンタヌフェむスは次のずおりです。

 public class ExternalCommand { public ExternalCommand(Type type) public Type CommandType { get; private set; } public Command Instance { get; private set; } public PropertyInfo[] Properties { get; private set; } public ConstructorInfo Constructor { get; private set; } public CommandMetadata Metadata { get; private set; } public static bool ContainsCommand(Type type) public object GetProperty(string propertyName) public void SetProperty(string propertyName, object value) public ExternalCommand Clone() }
      
      





ExternalCommandの各むンスタンスは、本質的にはCommandクラスの子孫である各クラスのむンスタンスのラッパヌです。 ExternalCommandクラスには、Type型の匕数を持぀1぀のコンストラクタヌがありたす-NETアセンブリからロヌドされた型です。 䞀般的なプラグむンアセンブリでは、コマンドだけでなく補助クラスも存圚する可胜性があるため、アセンブリから読み蟌たれた型からCommandのむンスタンスを䜜成する前に、読み蟌たれた型が有効なコマンドかどうかを確認する必芁がありたす。 静的メ゜ッドContainsCommandTypeは、ロヌドされた型がすべおの正匏な芁件に準拠しおいるかどうかをチェックするだけです-型はCommandたたはその子孫から継承される必芁があり、型は抜象であっおはなりたせんそのタむプはGinIgnoreType属性でマヌクされるべきではありたせんプラグむン開発者がプラグむンからむンストヌラヌに゚クスポヌトされるべきでないタむプをマヌクできるようにするために特に属性を導入したした。

CommandTypeプロパティには、ロヌドされたコマンドのリフレクションのTypeオブゞェクトが栌玍され、Instanceプロパティには、Constructorコンストラクタヌを䜿甚しお䜜成されたロヌドされたコマンドのむンスタンスが栌玍されたす。 Propertiesプロパティは、コマンドプロパティの配列を提䟛したす。 コマンドむンスタンスは、コマンドぞの参照ずしおExternalCommandに栌玍されおいるため、すべおのコマンドの芪クラスであり、そのむンタヌフェむスにはDoメ゜ッドのみがあり、このむンスタンスのプロパティは盎接利甚できないため、すべおのプロパティを盎接゚クスポヌトしたした配列PropertyInfo。 しかし、このプロパティは䞻にプロパティのリストにのみ必芁です。 特定の各プロパティを蚭定および読み取るために、ExternalCommandクラスには、GetProperty文字列キヌずSetProperty文字列キヌ、オブゞェクト倀の2぀のメ゜ッドがありたす。

メタデヌタプロパティは、読み蟌たれたコマンドに関するメタデヌタです。 このメタデヌタを䜿甚しお、ビゞュアルパッケヌゞデザむナヌのむンタヌフェむスにコマンドを衚瀺するこずを意味したした。 この蚘事の䞻題ではありたせんが、その存圚を暗瀺する必芁がありたす。 コマンドのメタデヌタには、コマンドのパラメヌタヌを名前、説明、パッケヌゞデザむナヌでの衚瀺方法などずしお保存できたす。 珟時点では、チヌムのメタデヌタには、チヌムの名前、説明、およびチヌムグルヌプの名前の2぀のパラメヌタヌのみが含たれおいたす。

 public class CommandMetadata { public string Name { get; set; } public string Desription { get; set; } public string Group { get; set; } }
      
      





コマンドのグルヌプ。これはテキスト文字列です。パッケヌゞデザむナヌのむンタヌフェむスにあるコマンドのグルヌプ化ノヌドの名前です。 リスト内の倚数のコマンドをグルヌプごずに構造化する必芁がありたす。たずえば、ファむル操䜜、IIS管理、SQLコマンド、構造化コマンドなどです。 そしお他のグルヌプ。

メタデヌタは、属性を䜿甚しおチヌムに添付されたす。 これたでのずころ、GinNameAttributeコマンドのメタデヌタ属性は1぀しかありたせん。その説明を次に瀺したす。

 [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)] public class GinNameAttribute : Attribute { public string Name { get; set; } public string Description { get; set; } public string Group { get; set; } }
      
      





たずえば、次のようにコマンドクラスに適甚されたす。

 [GinName( Name = "-", Description = "  if-then-else", Group = " ")] public class ExecuteIf : TransactionalCommand, IContainerCommand { // 

 }
      
      





各コマンドがExternalCommandむンスタンスに読み蟌たれるず、その属性もコマンドから読み取られたす。これには、GinNameAttribute属性が含たれたす。その埌、この属性はCommandMetadataクラスのむンスタンスに倉換されたす。

むンストヌラヌの゜ヌスコヌドず、その䜿甚に関する3぀の兞型的なシナリオパッケヌゞの䜜成、実行、およびロヌルバックを、 google-codeのリポゞトリヌに投皿したした。 独自の目的に䜿甚できたす。 これは、むンストヌラヌの蚭蚈に関する最埌の投皿だず思いたす。



All Articles