📜 ⬆️ ⬇️

Laziness, reflection, attributes, dynamic assemblies

A little experience from laziness.


About three years ago, I worked for one firm. There were 4 of us programmers. One wrote a business application logic. He described it using interfaces. Logical links, dependencies, etc. Our task was to implement these interfaces and link them to the GUI. The main problem in this system was the constant changes in the structure of relations and parameters. That is, we had to constantly engage in editing and refactoring.

I'm a lazy person. Therefore, the thought came - is it really impossible to automate it somehow? And I sat down at the books.

Step one
')
The first idea was sufficiently explicit and simple. Interfaces are contained in separate files - so why not parse them and create a text file with the generated class. That was done.

Unfortunately, those source codes are not preserved, but there is an analogue to whom it may be interesting to see (classes are built on the basis of tables from a database)

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; } } } /// <summary> ///    CreatorDBWorkClasses /// </summary> public class CreatorClasses { String connStr = null; public CreatorClasses(string table, String ConnectionString = null) { tablename = table; className = "cl_" + tablename; if (string.IsNullOrEmpty(ConnectionString)) connStr = v2_SacuraConstants.ConnectionString; else connStr = ConnectionString; // // TODO:    // } string mBaseClass = "DataBaseWorkBase"; public string BaseClass { get { return mBaseClass; } set { mBaseClass = value; } } string tab = "\t\t"; string className; string sources; public string Sources { get { return sources; } } string tablename; List<ColumnDB> mListColumn = new List<ColumnDB>(); public bool GetSources() { sources = "\tpublic class " + className + (string.IsNullOrEmpty(BaseClass) ? "" : " : " + BaseClass) + ", IDisposable\r\n\t{\r\n"; sources += GetConstructor(); sources += GetProperty(); sources += GetInitFunction(); sources += GetSaveFunction(); sources += GetDeleteFunction(); sources += GetDisposable(); sources += StaticGetList(); sources += GetLastError(); sources += "\t}"; return true; } string GetLastError() { return "#region Error\r\n" + " string mError;\r\n" + " public string lastError\r\n" + " {\r\n" + " get { return mError; }\r\n" + " }\r\n" + "#endregion\r\n"; } string StaticGetList() { return "#region Static_GetList\r\n" + " public static List<"+className+"> GetList(string SQL_WHERE = \"\")\r\n" + " {\r\n" + " List<" + className + "> lst = null;\r\n" + " DataBaseWorkBase db = new DataBaseWorkBase(v2_SacuraConstants.ConnectionString);\r\n" + " if (db.Open())\r\n" + " {\r\n" + " lst = new List<" + className + ">();\r\n" + " SqlCommand sqlcmd = db.CreateSQLCommand();\r\n" + " sqlcmd.CommandText = \"SELECT * \" +\r\n" + " \"FROM "+tablename+" \" + SQL_WHERE;\r\n" + " SqlDataReader reader = sqlcmd.ExecuteReader();\r\n" + " while (reader.Read())\r\n" + " {\r\n" + " " + className + " ord = new " + className + "();\r\n" + " if (ord.InitFromDataReader(reader))\r\n" + " lst.Add(ord);\r\n" + " }\r\n" + " reader.Close();\r\n" + " reader = null;\r\n" + " }\r\n" + " db.Close();\r\n" + " db = null;\r\n" + " return lst;\r\n" + " }\r\n" + "#endregion\r\n"; } string GetDisposable() { return "#region  IDisposable\r\n" + " public override void Close()\r\n" + " {\r\n" + " base.Close();\r\n" + " }\r\n" + "\r\n" + " protected override void Dispose(bool disposing)\r\n" + " {\r\n" + " if (disposing)\r\n" + " {\r\n"+ " Close();\r\n" + " base.Dispose(true);\r\n" + " }\r\n" + " }\r\n" + "#endregion\r\n"; } string GetDeleteFunction() { string con = "#region Delete\r\n"+ tab+"public bool Delete()\r\n"+ tab+"{\r\n"+ tab+" bool result = false;\r\n"+ tab+" try\r\n"+ tab+" {\r\n"+ tab+" SqlCommand sqlcmd = CreateSQLCommand();\r\n"+ tab+" sqlcmd.CommandText = \"DELETE FROM "+tablename+" WHERE ID=@ID\";\r\n"+ tab+" sqlcmd.Parameters.AddWithValue(\"@ID\", m_ID);\r\n"+ tab+" sqlcmd.ExecuteNonQuery();\r\n"+ tab+" result = true;\r\n"+ tab+" }\r\n"+ tab+" catch (System.Exception ex)\r\n"+ tab+" {\r\n"+ tab+" }\r\n"+ tab+" return result;\r\n"+ tab+"}\r\n"+ "#endregion\r\n"; return con; } string GetInitParams() { string pr = ""; int cnt = mListColumn.Count; for (int a = 0; a < cnt; a++) { if (mListColumn[a].Type != "string") pr += tab + tab + mListColumn[a].Type + ".TryParse(reader[" + a.ToString() + "].ToString(), out m_" + mListColumn[a].Name + ");\r\n"; else pr += tab + tab + mListColumn[a].Name +"=reader[" + a.ToString() + "].ToString();\r\n"; } return pr; } string GetInitFunction() { string fn = "#region Init\r\n" + tab + "public bool InitFromDataReader(SqlDataReader reader)\r\n" + tab + "{\r\n" + tab + " try\r\n" + tab + " {\r\n" + GetInitParams() + tab + " }\r\n" + tab + " catch (System.Exception ex)\r\n" + tab + " {\r\n" + tab + " return false;\r\n" + tab + " }\r\n" + tab + " return true;\r\n" + tab + "}\r\n" + tab + "public bool Init(string id)\r\n" + tab + "{\r\n" + tab + " if (string.IsNullOrEmpty(id))\r\n" + tab + " return false;\r\n" + tab + " int t;\r\n" + tab + " int.TryParse(id, out t);\r\n" + tab + " return Init(t);\r\n" + tab + "}\r\n" + tab + "public bool Init(int id)\r\n" + tab + "{\r\n" + tab + " if (!base.Open())\r\n" + tab + " return false;\r\n" + tab + " bool IsLoad = false;\r\n" + tab + " try\r\n" + tab + " {\r\n" + tab + " SqlCommand sqlcmd = CreateSQLCommand();\r\n" + tab + " sqlcmd.CommandText = \"SELECT * \" +\r\n" + tab + " \"FROM " + tablename + " WHERE [ID]=@ID\";\r\n" + tab + " sqlcmd.Parameters.AddWithValue(\"@ID\", id);\r\n" + tab + " SqlDataReader reader = sqlcmd.ExecuteReader();\r\n" + tab + " if (reader.Read())\r\n" + tab + " {\r\n" + tab + " if (!InitFromDataReader(reader))\r\n" + tab + " {\r\n" + tab + " reader.Close();\r\n" + tab + " base.Close();\r\n"+ tab + " return false;\r\n" + tab + " }\r\n" + tab + " IsLoad = true;\r\n" + tab + " }\r\n" + tab + " reader.Close();\r\n" + tab + " }\r\n" + tab + " catch (System.Exception ex)\r\n" + tab + " {\r\n" + tab + " mError = ex.Message;\r\n" + tab + " IsLoad = false;\r\n" + tab + " }\r\n" + tab + " base.Close();" + tab + " return IsLoad;\r\n" + tab + "}\r\n"; fn += "#endregion\r\n"; return fn; } string GetConstructor() { string con = "#region Constructor\r\n" + tab + "public " + className + "(string ConnectionString)\r\n" + tab + "\t: base (ConnectionString)\r\n" + tab + "{\r\n" + tab + "}\r\n" + tab + "public " + className + "()\r\n" + tab + "\t:base(v2_SacuraConstants.ConnectionString)\r\n" + tab + "{\r\n" + tab + "}\r\n" + "#endregion\r\n"; return con; } string GetProperty() { mListColumn.Clear(); string src = "#region Property\r\n"; ////////////////////////////////////////////////////////////////////////// //add property SqlConnection myConnection = new SqlConnection(connStr); SqlDataAdapter myAdapter = new SqlDataAdapter("select * from " + tablename, myConnection); DataSet dataSet = new DataSet(); myConnection.Open(); myAdapter.Fill(dataSet, "tablename"); myConnection.Close(); ConstraintCollection prKey = dataSet.Tables[0].Constraints; for (int i = 0; i < dataSet.Tables[0].Columns.Count; i++) { string tab1 = "\t\t\t"; src += tab; ColumnDB clTp = new ColumnDB(dataSet.Tables[0].Columns[i].ColumnName, dataSet.Tables[0].Columns[i].DataType.Name); mListColumn.Add(clTp); src += clTp.Type + " m_" + clTp.Name +"="+clTp.Initial+ ";\r\n"; src += "\t\t"; src += "public "+clTp.Type + " " + clTp.Name + "\r\n" + tab + "{\r\n" + tab1 + "get\r\n" + tab1 + "{\r\n" + tab1 + "\treturn m_" + clTp.Name + ";\r\n" + tab1 + "}\r\n" + tab1 + "set\r\n" + tab1 + "{\r\n" + tab1 + "\tm_" + clTp.Name + "=value;\r\n" + tab1 + "}\r\n" + tab + "}\r\n"; } ////////////////////////////////////////////////////////////////////////// return src + "#endregion\r\n"; } string GetSaveInsertParams() { string pr = ""; int cnt = mListColumn.Count; for (int a = 1; a < cnt; a++) { pr += tab + tab + tab + (a == 1 ? "\"[" : "\",[") + mListColumn[a].Name + "]\"+\r\n"; } return pr; } string GetSaveInsertValues() { string pr = ""; int cnt = mListColumn.Count; for (int a = 1; a < cnt; a++) { pr += tab + tab + tab + (a == 1 ? "\"@" : "\",@") + mListColumn[a].Name + (a != cnt - 1 ? "\"+\r\n" : ")\""); } return pr; } string GetSaveUpdateParams() { string pr = ""; int cnt = mListColumn.Count; for (int a = 1; a < cnt; a++) { pr += tab + tab + tab + (a == 1 ? "\"[" : "\",[") + mListColumn[a].Name + "]=@" + mListColumn[a].Name + "\"" + (a != cnt - 1 ? "+\r\n" : ""); } return pr; } string GetAddWithValue() { string pr = ""; int cnt = mListColumn.Count; for (int a = 1; a < cnt; a++) { pr += tab + tab + "sqlcmd.Parameters.AddWithValue(\"@" + mListColumn[a].Name +"\", m_"+ mListColumn[a].Name+");\r\n"; } return pr; } string GetSaveFunction() { string con = "#region Save\r\n" + tab + "public bool Save()\r\n" + tab + " {\r\n" + tab + " bool result = false;\r\n" + tab + " try\r\n" + tab + " {\r\n" + tab + " SqlCommand sqlcmd = CreateSQLCommand();\r\n" + tab + " if (m_ID <= 0)\r\n" + tab + " {\r\n" + tab + " sqlcmd.CommandText = \"INSERT INTO " + tablename + " ( \"+\r\n" + GetSaveInsertParams() + tab + " \") VALUES (\"+\r\n" + GetSaveInsertValues() + "+\";SELECT CAST(scope_identity() AS int)\";\r\n" + tab + " }\r\n" + tab + " else\r\n" + tab + " {\r\n" + tab + " sqlcmd.CommandText = \"UPDATE " + tablename + " SET \" +\r\n" + GetSaveUpdateParams() + "+\r\n" + tab + " \" WHERE ID=@ID\";\r\n" + tab + " sqlcmd.Parameters.AddWithValue(\"@ID\", m_ID);\r\n" + tab + " }\r\n" + tab + GetAddWithValue() + "\r\n" + tab + " if (m_ID > 0)\r\n" + tab + " sqlcmd.ExecuteNonQuery();\r\n" + tab + " else\r\n" + tab + " {\r\n" + tab + " object ob;\r\n" + tab + " ob = sqlcmd.ExecuteScalar();\r\n" + tab + " if(ob != null)\r\n" + tab + " int.TryParse(ob.ToString(), out m_ID);\r\n" + tab + " }\r\n" + tab + " }\r\n" + tab + " catch (System.Exception ex)\r\n" + tab + " {\r\n" + tab + " mError = ex.Message;\r\n" + tab + " result = false;\r\n" + tab + " }\r\n" + tab + " return result;\r\n" + tab + " }\r\n" + "#endregion\r\n"; return con; } } } 


It seems that the problem is solved. Nevertheless, there was still a lot of work left: file transfer, refactoring. Yes, the guys have not changed anything. They were involved in creating the UI and binding it to the object model.

Step two

Continuing the search in the network, I came across the description of the class Type , becoming interested, I read about it in more detail. There are many interesting features in this class. In fact, thanks to him you can get all the information on the class. Designer, implemented interfaces, properties, variables, functions ... Full information. And I began to experiment with it, and in the end, I got:

Class for working with class types

 using System; using System.Collections.Generic; using System.Reflection; using System.Threading; namespace SV.Tools { public delegate void AddProp(string name, string val); /// <summary> ///     /// </summary> public struct MetodInfoDouble { public MethodInfo getMetod; public MethodInfo setMetod; } /// <summary> ///         :(     /// </summary> public class ClassesTools { /// <summary> ///        /// </summary> /// <param name="ob"></param> /// <param name="delegateProp"></param> /// <param name="parentName"></param> public static void GetAllPropertyData(object ob, AddProp delegateProp, string parentName = "") { if (ob == null || delegateProp == null) return; PropertyInfo[] propInfo = ob.GetType().GetProperties(); for (int b = 0; b < propInfo.Length; b++) { ParameterInfo[] param = propInfo[b].GetIndexParameters(); if (param.Length == 0 && propInfo[b].CanRead && propInfo[b].Name != "Root" && propInfo[b].Name != "Parent") { object data = propInfo[b].GetValue(ob, null); if (propInfo[b].PropertyType.IsInterface && data != null) { GetAllPropertyData(data, delegateProp, (parentName == "" ? "" : parentName + ".") + propInfo[b].Name); } else { delegateProp((parentName == "" ? "" : parentName + ".") + propInfo[b].Name, ( data == null ? "NULL" : SV.ConversionTools.DataCoversion.ConvertByType(data))); } } } } static AppDomain domain = Thread.GetDomain(); static Assembly[] asm = domain.GetAssemblies(); /// <summary> ///     /// </summary> /// <param name="name"> </param> /// <returns></returns> public static Type FindInterfece(string Namespace, string Name, bool isIgnorCase = true) { if (Namespace == "" || Name == "") return null; int count = asm.Length; for (int a = 0; a < count; a++) { Type t = asm[a].GetType(Namespace+"."+Name); if (t != null) return t; } return null; } public static List<Type> GetAsseblyIntrface(string AssembleName, string Namespace) { if (Namespace == "" ) return null; int count = asm.Length; for (int a = 0; a < count; a++) { if (asm[a].GetName().Name == AssembleName) { Type[] t = asm[a].GetTypes(); List<Type> lst = new List<Type>(); count = t.Length; for(int b =0; b < count; b++) { if (t[b].Namespace == Namespace) lst.Add(t[b]); } return lst; } } return null; } /// <summary> ///   ,  ,   /// </summary> /// <param name="tp"></param> /// <param name="listInterfece"></param> public static void GetAllInterfece(Type[] tp, ref List<Type> listInterfece) { if (tp == null) return; int count = tp.Length; for (int a = 0; a < count; a++) { Type rezult = listInterfece.Find( delegate(Type typ) { return tp[a] == typ; } ); if (rezult == null) listInterfece.Add(tp[a]); Type[] t = tp[a].GetInterfaces(); GetAllInterfece(t, ref listInterfece); } } /// <summary> ///   ,   /// </summary> /// <param name="parentClass"></param> /// <returns></returns> public static List<Type> GetAllInterfece(Type parentClass) { List<Type> listClasses = new List<Type>(); GetAllInterfece(new Type[] { parentClass }, ref listClasses); return listClasses; } /// <summary> ///   ,  ,   /// </summary> /// <param name="parentClass"></param> /// <param name="listInterfece"></param> /// <returns></returns> public static List<Type> GetAllInterfece(Type parentClass, List<Type> listInterfece) { List<Type> listClasses = new List<Type>(); GetAllInterfece(new Type[] { parentClass }, ref listClasses); GetAllInterfece(listInterfece.ToArray(), ref listInterfece); return RemoveDouble(listClasses, listInterfece); } /// <summary> ///     /// </summary> /// <param name="sources"></param> /// <param name="editableList">       sources</param> /// <returns> </returns> public static List<Type> RemoveDouble(List<Type> sources, List<Type> editableList) { for (int a = editableList.Count - 1; a >= 0; a--) { if (sources.Find((Type t) => editableList[a] == t) != null) editableList.RemoveAt(a); } return editableList; } /// <summary> ///       /// </summary> /// <param name="_class"> </param> /// <param name="propertyName"> </param> /// <returns> </returns> /// <remarks> ///   /// </remarks> public static PropertyInfo FindProperty(Type _class, string propertyName) { List<PropertyInfo> allProperty = GetAllProperty(_class); int count = allProperty.Count; PropertyInfo info = null; for (int a = 0; a < count; a++) { if (allProperty[a].Name == propertyName) { info = allProperty[a]; break; } } return info; } public static List<Type> RemoveDouble(List<Type> property) { List<Type> retryList = new List<Type>(); int count = property.Count; for (int a = 0; a < count; a++) { if (retryList.Find((Type inf) => property[a] == inf) == null) retryList.Add(property[a]); } return retryList; } public static List<PropertyInfo> RemoveDouble(List<PropertyInfo> property) { List<PropertyInfo> retryList = new List<PropertyInfo>(); int count = property.Count; for (int a = 0; a < count; a++) { if(retryList.Find( (PropertyInfo inf) =>property[a] == inf ) == null) retryList.Add(property[a]); } return retryList; } /// <summary> ///     ,    /// </summary> /// <param name="interfeceList"> </param> /// <returns> </returns> /// <remarks> ///   /// </remarks> public static List<PropertyInfo> GetAllProperty(Type parent) { List<Type> allTypes = GetAllInterfece(parent); List<PropertyInfo> allProperty = new List<PropertyInfo>(); if (allTypes != null) { int count = allTypes.Count; for(int a =0; a < count; a++) { allProperty.AddRange(allTypes[a].GetProperties(/*BindingFlags.Default*/)); } } return RemoveDouble(allProperty); } /// <summary> ///     /// </summary> /// <param name="name"> </param> /// <returns></returns> public static PropertyInfo GetPropertyByName(object curr, string name, ref object objectIsCall) { if (curr == null) return null; PropertyInfo pI = curr.GetType().GetProperty(name); objectIsCall = curr; if (pI == null) { int t = name.IndexOf('.'); if (t > 0) { string curName = name.Substring(0, t); pI = curr.GetType().GetProperty(curName); if (pI != null) { name = name.Remove(0, t + 1); if (name.Length > 0) { object v = pI.GetValue(curr, null); if (v == null) return null; return GetPropertyByName(v, name, ref objectIsCall); } } } } return pI; } /// <summary> ///        /// </summary> /// <param name="interfeceList">  \</param> /// <param name="propertyInfo">  </param> /// <param name="memberInfo">  </param> /// <param name="fieldInfo">  </param> /// <param name="metodInfo">  </param> /// <param name="eventInfo">  </param> public static void GetInterfaceMetadata(List<Type> interfeceList, ref List<PropertyInfo> propertyInfo, ref List<MemberInfo> memberInfo, ref List<FieldInfo> fieldInfo, ref List<MethodInfo> metodInfo, ref List<EventInfo> eventInfo) { int count = interfeceList.Count; for (int a = 0; a < count; a++) { ////////////////////////////////////////////////////////////////////////// //    PropertyInfo[] propertyIE = interfeceList[a].GetProperties(); propertyInfo.AddRange(propertyIE); EventInfo[] events = interfeceList[a].GetEvents(); eventInfo.AddRange(events); MemberInfo[] membersIE = interfeceList[a].GetMembers(); memberInfo.AddRange(membersIE); FieldInfo[] fieldIE = interfeceList[a].GetFields(); fieldInfo.AddRange(fieldIE); MethodInfo[] metodIE = interfeceList[a].GetMethods(); metodInfo.AddRange(metodIE); } } /// <summary> ///     /// </summary> /// <param name="propertyInfoInterface"></param> /// <returns></returns> public static Dictionary<string, MetodInfoDouble> RemoveDoubleProperty(List<PropertyInfo> propertyInfoInterface) { if (propertyInfoInterface == null) return null; Dictionary<string, MetodInfoDouble> m_doubleList = new Dictionary<string, MetodInfoDouble>(); int count = propertyInfoInterface.Count - 1; for (int a = count; a >= 0; a--) { List<PropertyInfo> fnd = propertyInfoInterface.FindAll( (PropertyInfo inf) => inf.Name == propertyInfoInterface[a].Name); PropertyInfo fullMetod = null; MetodInfoDouble mDouble = new MetodInfoDouble(); mDouble.getMetod = null; mDouble.setMetod = null; if (fnd != null && fnd.Count > 1) { string tmp = ""; for (int b = 0; b < fnd.Count; b++) { tmp += fnd[b].ReflectedType.FullName + "\r\n"; propertyInfoInterface.Remove(fnd[b]); if (fnd[b].CanRead && fnd[b].CanWrite) fullMetod = fnd[b]; else if (fnd[b].CanRead) mDouble.getMetod = fnd[b].GetGetMethod(); else if (fnd[b].CanWrite) mDouble.setMetod = fnd[b].GetSetMethod(); } #if DEBUG //MessageBox.Show("DEBUG:\r\n   : " + fnd[0].Name + "\r\n :\r\n" + tmp); #endif if (fullMetod != null) propertyInfoInterface.Add(fullMetod); else { m_doubleList.Add(fnd[0].Name, mDouble); propertyInfoInterface.Add(fnd[0]); } } } return m_doubleList; } public static bool IsPrimitive(Type t) { if (t == null) return true; if (!t.IsClass && !t.IsInterface || t.IsPrimitive || t.IsEnum || t == typeof(String) || t == typeof(Guid) || t == typeof(DateTime)) return true; return false; } /// <summary> ///         /// </summary> /// <param name="propertyName"> </param> ///<param name="param"> </param> /// <returns>,   null       </returns> static public object GetData(object baseCalss,string propertyName, object[] param = null) { if (baseCalss == null || propertyName == null) return null; object RecalcOb = null; PropertyInfo _PropertyDescriptor = SV.Tools.ClassesTools.GetPropertyByName(baseCalss, propertyName.ToString(), ref RecalcOb); object v = null; if (_PropertyDescriptor != null) v = _PropertyDescriptor.GetValue((RecalcOb == null ? baseCalss : RecalcOb), param); return v; } /// <summary> ///       /// </summary> /// <param name="propertyName"> </param> /// <param name="newPropertyData"> </param> ///<param name="param"> </param> /// <returns>false -    </returns> static public bool SetData(object baseCalss, string propertyName, object newPropertyData, object[] param = null) { if (baseCalss == null || propertyName == null) return false; object RecalcOb = null; PropertyInfo _PropertyDescriptor = SV.Tools.ClassesTools.GetPropertyByName(baseCalss, propertyName, ref RecalcOb); if (_PropertyDescriptor == null) return false; object data = newPropertyData; if (newPropertyData != null && newPropertyData.GetType() != _PropertyDescriptor.PropertyType) data = SV.ConversionTools.DataCoversion.ConvertByType(data.ToString(), _PropertyDescriptor.PropertyType); _PropertyDescriptor.SetValue((RecalcOb == null ? baseCalss : RecalcOb), data, param); return true; } } } 


Now I could get all the information on any object and
even send and receive data in parameters simply by parameter name
  /// <summary> ///         /// </summary> /// <param name="propertyName"> </param> ///<param name="param"> </param> /// <returns>,   null       </returns> static public object GetData(object baseCalss,string propertyName, object[] param = null) { if (baseCalss == null || propertyName == null) return null; object RecalcOb = null; PropertyInfo _PropertyDescriptor = SV.Tools.ClassesTools.GetPropertyByName(baseCalss, propertyName.ToString(), ref RecalcOb); object v = null; if (_PropertyDescriptor != null) v = _PropertyDescriptor.GetValue((RecalcOb == null ? baseCalss : RecalcOb), param); return v; } /// <summary> ///       /// </summary> /// <param name="propertyName"> </param> /// <param name="newPropertyData"> </param> ///<param name="param"> </param> /// <returns>false -    </returns> static public bool SetData(object baseCalss, string propertyName, object newPropertyData, object[] param = null) { if (baseCalss == null || propertyName == null) return false; object RecalcOb = null; PropertyInfo _PropertyDescriptor = SV.Tools.ClassesTools.GetPropertyByName(baseCalss, propertyName, ref RecalcOb); if (_PropertyDescriptor == null) return false; object data = newPropertyData; if (newPropertyData != null && newPropertyData.GetType() != _PropertyDescriptor.PropertyType) data = SV.ConversionTools.DataCoversion.ConvertByType(data.ToString(), _PropertyDescriptor.PropertyType); _PropertyDescriptor.SetValue((RecalcOb == null ? baseCalss : RecalcOb), data, param); return true; } 


It was a breakthrough. A wrapper was created that was binding the data to the GUI by test structures. Development speed has increased significantly. In principle, it would be possible to calm down.
But I'm lazy.

Step Three

Sitting, like that, on Friday, in a bar, some sort of signboard advertisement rushed into my eyes. Something was there with the phrase ASM ... Blurred brain, immediately threw up the association: ASM - ASSEMBLER and immediately came up with the memory of the Common Intermediate Language , followed by IL Disassembler . Throwing friends and a bar, I ran home, not forgetting, however, to bring along a couple of liters of beer for stimulation.

Class ILGenerator
At home, after reading the information on this class, I realized - this is it.

I twist, turning, I want something and turn back

Having collected all the information in a bunch, I got down to business.

First and foremost, creating a console project with the simplest code

  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) { } } 


I looked at what it is deploying with Ildasm.exe (IL Disassembler)

ASM code:


 .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 


Having scratched my turnips a little bit, I created a class for generating dynamic objects based on the transferred: base class (any) and interface list:

Link to the project on GitHub

I will describe the project a little


Formation of object properties:

Get

  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 } 


SET

 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 } 


From current features:

The formation of dynamic classes of objects based on the transferred: base class and list of interfaces, the ability to save these objects in a separate library (dll), through the BuilderClassesPropertyAttribyte of the Attribute successor, can be set for the built-in object parameters different inheritance and behavior. Formation and initialization of class objects is done with a lot of nested objects.

I plan in the future:

To give the possibility to form objects from several classes and interfaces. I really didn’t have enough after C ++ this.

Source: https://habr.com/ru/post/316238/


All Articles