這裡有兩個問題點:
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.CodeDom
using 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);
//指定这是一个Class
Customerclass.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