欄位未知的Datatable轉成ObserObservableCollection<T>對象
這裡有兩個問題點:
1.如何將Datatable各欄位名稱和數據類型動態生成 一個類的實例.
2.如何將類的實例(變量,不是類型)作為T(泛型)傳入,並返回為T;
解決辦法:
第一步.判斷當前程序集,有無要生成的類,
A.如果有,則動態調用類的實例,
B.如果沒有,則生成代碼文件(供下次編譯時,直接編譯成類即可,提升代碼運行效率),再將代碼文件動態編譯成類,再調用;
第二步.在第一步得到的類是類的實例,不是類型,需要將實例透過轉化為類型T;
代碼如下:
#region 生成自定义动态类
public class Dyn_CreateClass{private DataTable ThisDt;private string ForCreateClassName;string Mynamespace= System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Namespace;public Dyn_CreateClass(string CreateClassname, DataTable SourceDt){if (CreateClassname.IndexOf("_") == -1){MessageBox.Show("要創建的類名不符合要求");}this.ForCreateClassName = CreateClassname;ThisDt = SourceDt.Clone();}private class ColumnInfor{public string Name { get; set; }public Type datatype { get; set; }}private List<ColumnInfor> GetDatatableColsinfor(){List<ColumnInfor> lc = new List<ColumnInfor>();foreach (DataColumn item in ThisDt.Columns){lc.Add(new ColumnInfor() { Name = item.ColumnName, datatype = item.DataType });}return lc;}public bool FindClassInthisApp(){Assembly assm3 = Assembly.GetExecutingAssembly();string assemblyname = assm3.GetName().Name;Type[] typesToRegister = assm3.GetTypes().Where(type => !String.IsNullOrEmpty(type.Namespace)).Where(type => type.FullName.Contains(assemblyname)).Where(tppe => tppe.Name == ForCreateClassName).ToArray<Type>();return typesToRegister.Length > 0;}private object CreateClass(Assembly assembly){Type type = assembly.GetType(Mynamespace+"."+ForCreateClassName);// 创建该类的实例object obj = Activator.CreateInstance(type);// 返回新创建的类return obj;}private object Dyn_LoadClass(){Assembly assembly = Assembly.GetExecutingAssembly(); // 获取当前程序集Type o = Type.GetType(Mynamespace + "." + ForCreateClassName);//加载类型object obj = Activator.CreateInstance(o, true);//根据类型创建实例return obj;}public object GenerateCode(){if (FindClassInthisApp())return Dyn_LoadClass();/*注意,先导入下面的命名空间using System.CodeDomusing System.CodeDom.Compiler;using Microsoft.CSharp;using System.Reflection;*///准备一个代码编译器单元CodeCompileUnit unit = new CodeCompileUnit();//准备必要的命名空间(这个是指要生成的类的空间)CodeNamespace sampleNamespace = new CodeNamespace(Mynamespace);//导入必要的命名空间// sampleNamespace.Imports.Add(new CodeNamespaceImport("System"));//准备要生成的类的定义CodeTypeDeclaration Customerclass = new CodeTypeDeclaration(ForCreateClassName);//指定这是一个ClassCustomerclass.IsClass = true;Customerclass.TypeAttributes = TypeAttributes.Public;//把这个类放在这个命名空间下sampleNamespace.Types.Add(Customerclass);//把该命名空间加入到编译器单元的命名空间集合中unit.Namespaces.Add(sampleNamespace);//这是输出文件string outputFile = "../../../AutoCreateClass/" + ForCreateClassName+".cs";添加字段List<ColumnInfor> datainfor = GetDatatableColsinfor();datainfor.ForEach(column =>{CodeMemberField field = new CodeMemberField(column.datatype, column.Name +" { get; set; }//");field.Attributes = MemberAttributes.Public;Customerclass.Members.Add(field);});CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");CodeGeneratorOptions options = new CodeGeneratorOptions();options.BracingStyle = "C";options.BlankLinesBetweenMembers = true;using (System.IO.StreamWriter sw = new System.IO.StreamWriter(outputFile)){provider.GenerateCodeFromCompileUnit(unit, sw, options);}string treefile= File.ReadAllText(outputFile);Assembly newassamly=GenerateAssemblyFromCode(treefile); ;return CreateClass(newassamly);}public static Assembly GenerateAssemblyFromCode(string code){Assembly assembly = null;// 丛代码中转换表达式树SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(code);// 随机程序集名称string assemblyName = System.IO.Path.GetRandomFileName();// 引用// var references = AppDomain.CurrentDomain.GetAssemblies().Select(x => MetadataReference.CreateFromFile(x.Location));MetadataReference[] references = new MetadataReference[]
{MetadataReference.CreateFromFile(typeof(object).Assembly.Location),MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location)
};try{// 创建编译对象CSharpCompilation compilation = CSharpCompilation.Create(assemblyName, new[] { syntaxTree }, references, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));using (var ms = new MemoryStream()){// 将编译好的IL代码放入内存流EmitResult result = compilation.Emit(ms);// 编译失败,提示if (!result.Success){IEnumerable<Diagnostic> failures = result.Diagnostics.Where(diagnostic =>diagnostic.IsWarningAsError ||diagnostic.Severity == DiagnosticSeverity.Error);foreach (Diagnostic diagnostic in failures){Console.Error.WriteLine("{0}: {1}", diagnostic.Id, diagnostic.GetMessage());}}else{// 编译成功,从内存中加载编译好的程序集ms.Seek(0, SeekOrigin.Begin);assembly = Assembly.Load(ms.ToArray());}}}catch (Exception ex){}return assembly;}/// <summary>/// 给属性赋值/// </summary>/// <param name="objclass">先进行dynamic objclass = assembly.CreateInstance(className),得到的objclass</param>/// <param name="propertyname">属性名称</param>/// <param name="value">属性值</param>public static void ReflectionSetValue(object objclass, string propertyname, object value){PropertyInfo[] infos = objclass.GetType().GetProperties();try{foreach (PropertyInfo info in infos){if (info.Name == propertyname && info.CanWrite){info.SetValue(objclass, value, null);}}}catch (Exception ex){System.Diagnostics.Debug.WriteLine(ex.Message);}}/// <summary>/// 得到属性值/// </summary>/// <param name="objclass">先进行dynamic objclass = assembly.CreateInstance(className),得到的objclass</param>/// <param name="propertyname">属性名称</param>/// <returns>属性值,是object类型,使用时记得转换</returns>public static object ReflectionGetValue(object objclass, string propertyname){object result = null;PropertyInfo[] infos = objclass.GetType().GetProperties();try{foreach (PropertyInfo info in infos){if (info.Name == propertyname && info.CanRead){System.Console.WriteLine(info.GetValue(objclass, null));result = info.GetValue(objclass, null);}}}catch (Exception ex){System.Diagnostics.Debug.WriteLine(ex.Message);result = null;}return result;}}#endregion
#region 類實例轉化為T,並將傳入的Datatable變為ObservableCollection<T>傳出public class TConverter{public object Deserializer<T>(DataTable dt) where T : class, new(){Type t = typeof(T);PropertyInfo[] propertys = t.GetProperties();ObservableCollection<T> lst = new ObservableCollection<T>();string typeName = string.Empty;foreach (DataRow dr in dt.Rows){T entity = new();foreach (PropertyInfo pi in propertys){typeName = pi.Name;if (dt.Columns.Contains(typeName)){if (!pi.CanWrite) continue;object value = dr[typeName];if (value == DBNull.Value) continue;if (pi.PropertyType == typeof(string)){pi.SetValue(entity, value.ToString(), null);}else if (pi.PropertyType == typeof(int) || pi.PropertyType == typeof(int?)){pi.SetValue(entity, int.Parse(value.ToString()), null);}else if (pi.PropertyType == typeof(DateTime?) || pi.PropertyType == typeof(DateTime)){pi.SetValue(entity, DateTime.Parse(value.ToString()), null);}else if (pi.PropertyType == typeof(float)){pi.SetValue(entity, float.Parse(value.ToString()), null);}else if (pi.PropertyType == typeof(double)){pi.SetValue(entity, double.Parse(value.ToString()), null);}else{pi.SetValue(entity, value, null);}}}lst.Add(entity);}return lst;}}public static class Extend{public static object ToObservable匿名類(this DataTable dt,object obj ){Type type = obj.GetType();TConverter Td = new TConverter();MethodInfo Method = Td.GetType().GetMethod("Deserializer").MakeGenericMethod(new Type[] { type });object[] _args = new object[1] { dt };return Method.Invoke(Td, _args);}
}#endregion