怠throughによって得られる経験はほとんどありません
3年前、私は1つの会社で働きました。 プログラマーは4人いました。 1つはビジネスアプリケーションロジックを記述しました。 彼はそれをインターフェースを使って説明しました。 論理接続、依存関係など。私たちのタスクは、これらのインターフェイスを実装し、GUIに接続することでした。 このシステムの主な問題は、関係とパラメーターの構造が絶えず変化することでした。 つまり、私たちは常に編集とリファクタリングに対処しなければなりませんでした。
私は怠け者です。 したがって、考えが来ました-これをどうにかして自動化することは本当に不可能ですか? そして、私は本に座った。
最初のステップ最初のアイデアは明確でシンプルでした。 インターフェースは別々のファイルに含まれています-なぜそれらを解析して、生成されたクラスでテキストファイルを作成しないのですか。 それで終わった。
残念ながら、それらのソースコードは保存されませんでしたが、見たい人には類似物があります(クラスはデータベースのテーブルに基づいて構築されます)using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Data; using SV.DataBaseWork; using v2; using System.Data.SqlClient; namespace CreatorDBClasses { class ColumnDB { public ColumnDB(string name, string type) { Name = name; Type = ConvertType(type); } public string Name; public string Type; public string Initial = "null"; public string ConvertType(string tp) { switch (tp) { case "String": Initial = "\"\""; return "string"; case "Double": Initial = "0"; return "double"; case "Boolean": Initial = "false"; return "bool"; case "Int32": Initial = "0"; return "int"; default: Initial = "null"; return tp; } } }
問題は解決されたようです。 それでも、ファイル転送、リファクタリングなど、まだ多くの作業がありました。 はい、彼らは何も変えていません。 彼らは、UIの作成とオブジェクトモデルへのバインドに関与していました。
第二段階ネット上で検索を続けると
、Typeクラスの説明に出会い
、興味を持ち、それについてさらに読みました。 このクラスには多くの興味深い機能があります。 実際、彼のおかげで、クラスに関するすべての情報を完全に入手できます。 コンストラクター、実装されたインターフェイス、プロパティ、変数、関数...完全な情報。 そして、私は彼と実験を始めました、そして、最終的に、私は得ました:
クラス型を操作するためのクラス
using System; using System.Collections.Generic; using System.Reflection; using System.Threading; namespace SV.Tools { public delegate void AddProp(string name, string val);
これで、オブジェクトに関するすべての情報を完全に取得でき、
パラメータ名だけでパラメータとデータを送受信することもできます それは突破口でした。 テスト構造によってGUIにデータバインディングを行うラッパーが作成されました。 開発速度が大幅に向上しました。 原則として、落ち着くことができます。
しかし、私は怠け者です。第三段階そのように、金曜日にバーに座って、ある種の広告サインが目を引きました。 ASMというフレーズがありました...霧の脳はすぐに関連性を失いました。ASM-ASSEMBLERと
Common Intermediate Languageの記憶が表面化し、
IL Disassemblerが続きました。 友人とバーを投げて、私は家に走りましたが、刺激のために数リットルのビールを持参することを忘れませんでした。
クラスILGenerator自宅で、このクラスの情報を読んだ後、私は気づいた-これはそれだ。
ひねりながら回したいすべての情報をひとまとめにして、仕事に取りかかりました。
まず最初に、簡単なコードでコンソールプロジェクトを作成します interface iT { int i { get; set; } } class cT : iT { int t = 0; public int i { get { return t; } set { t = value; } } } class Program { static void Main(string[] args) { } }
Ildasm.exe(IL逆アセンブラー)で展開しているものを見ました
ASMコード:
.class interface private abstract auto ansi ILG.iT { .method public hidebysig newslot specialname abstract virtual instance int32 get_i() cil managed { } // end of method iT::get_i .method public hidebysig newslot specialname abstract virtual instance void set_i(int32 'value') cil managed { } // end of method iT::set_i .property instance int32 i() { .get instance int32 ILG.iT::get_i() .set instance void ILG.iT::set_i(int32) } // end of property iT::i } // end of class ILG.iT .class private auto ansi beforefieldinit ILG.cT extends [mscorlib]System.Object implements ILG.iT { .field private int32 t .method public hidebysig newslot specialname virtual final instance int32 get_i() cil managed { // .maxstack 1 .locals init ([0] int32 V_0) IL_0000: nop IL_0001: ldarg.0 IL_0002: ldfld int32 ILG.cT::t IL_0007: stloc.0 IL_0008: br.s IL_000a IL_000a: ldloc.0 IL_000b: ret } // end of method cT::get_i .method public hidebysig newslot specialname virtual final instance void set_i(int32 'value') cil managed { // .maxstack 8 IL_0000: nop IL_0001: ldarg.0 IL_0002: ldarg.1 IL_0003: stfld int32 ILG.cT::t IL_0008: ret } // end of method cT::set_i .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { // .maxstack 8 IL_0000: ldarg.0 IL_0001: ldc.i4.0 IL_0002: stfld int32 ILG.cT::t IL_0007: ldarg.0 IL_0008: call instance void [mscorlib]System.Object::.ctor() IL_000d: nop IL_000e: ret } // end of method cT::.ctor .property instance int32 i() { .get instance int32 ILG.cT::get_i() .set instance void ILG.cT::set_i(int32) } // end of property cT::i } // end of class ILG.cT
カブを少しひっかいた後、転送されたオブジェクトに基づいて動的オブジェクトを生成するためのクラスを作成しました:基本クラス(any)とインターフェースのリスト:
→
GitHubのプロジェクトへのリンクプロジェクトについて少し説明します
オブジェクトプロパティの形成:ゲット void CreatePropertyGetMetod(PropertyInfo property, PropertyBuilder custNamePropBldr, FieldBuilder fieldProperty, object redirectData) { #region GET_METOD // MethodInfo inf = property.GetGetMethod(); // if (inf == null) { if (m_doubleList.ContainsKey(property.Name)) inf = m_doubleList[property.Name].getMetod; } // if (inf != null) { // MethodBuilder custNameGetPropMthdBldr = m_TypeBuilder.DefineMethod("get_" + property.Name, m_getSetAttr, property.PropertyType, Type.EmptyTypes); // ILGenerator custNameGetIL = custNameGetPropMthdBldr.GetILGenerator(); System.Reflection.Emit.Label end = custNameGetIL.DefineLabel(); // custNameGetIL.Emit(OpCodes.Nop); custNameGetIL.Emit(OpCodes.Ldarg_0); // custNameGetIL.Emit(OpCodes.Ldfld, fieldProperty); // custNameGetIL.Emit(OpCodes.Ret); // m_TypeBuilder.DefineMethodOverride(custNameGetPropMthdBldr, inf); // custNamePropBldr.SetGetMethod(custNameGetPropMthdBldr); } // ////////////////////////////////////////////////////////////////////////// #endregion }
セット void CreatePropertySetMetod(PropertyInfo property, PropertyBuilder custNamePropBldr, FieldBuilder fieldProperty, object redirectData) { #region SET_METOD // MethodInfo inf = property.GetSetMethod(); // if (inf == null) { if (m_doubleList != null && m_doubleList.ContainsKey(property.Name)) inf = m_doubleList[property.Name].setMetod; } if (inf != null) { MethodBuilder custNameSetPropMthdBldr = m_TypeBuilder.DefineMethod("set_" + property.Name, m_getSetAttr, null, new Type[] { property.PropertyType }); ILGenerator custNameSetIL = custNameSetPropMthdBldr.GetILGenerator(); // custNameSetIL.Emit(OpCodes.Ldarg_0); if (fieldProperty != null) { LocalBuilder loc = custNameSetIL.DeclareLocal(property.PropertyType); custNameSetIL.Emit(OpCodes.Ldfld, fieldProperty); custNameSetIL.Emit(OpCodes.Stloc_0); custNameSetIL.Emit(OpCodes.Ldarg_0); custNameSetIL.Emit(OpCodes.Ldarg_1); // custNameSetIL.Emit(OpCodes.Stfld, fieldProperty); if (m_baseClass.GetInterface("iMatryoshkaCall") != null) { MethodInfo simpleShow = typeof(iMatryoshkaCall).GetMethod("CallPropertyChange"); //CallPropertyChange(string propertyName, object CommandID = null, object oldData = null, object newData = null) if (simpleShow != null) { custNameSetIL.Emit(OpCodes.Ldarg_0); custNameSetIL.Emit(OpCodes.Ldstr, property.Name); custNameSetIL.Emit(OpCodes.Ldc_I4_0); custNameSetIL.Emit(OpCodes.Box, typeof(int)); custNameSetIL.Emit(OpCodes.Ldloc_0); custNameSetIL.Emit(OpCodes.Box, property.PropertyType); custNameSetIL.Emit(OpCodes.Ldarg_0); custNameSetIL.Emit(OpCodes.Ldfld, fieldProperty); custNameSetIL.Emit(OpCodes.Box, property.PropertyType); custNameSetIL.Emit(OpCodes.Callvirt, simpleShow); } } } custNameSetIL.Emit(OpCodes.Ret); custNamePropBldr.SetSetMethod(custNameSetPropMthdBldr); m_TypeBuilder.DefineMethodOverride(custNameSetPropMthdBldr, inf); } #endregion }
現在の機能から:転送されたものに基づいた動的オブジェクトクラスの形成:基本クラスとインターフェイスのリスト、これらのオブジェクトを別のライブラリ(dll)に保存する機能、
Attribute子孫のBuilderClassesPropertyAttribyteを介して、組み込みオブジェクトパラメーターのさまざまな継承と動作を指定できます。 クラスオブジェクトの形成と初期化は、多くのネストされたオブジェクトで実行されます。
私は将来計画します:いくつかのクラスとインターフェースからオブジェクトを作成する機会を与えるために、C ++の後は本当に見逃しました。