[Reflection][C# .NET]利用反射来简化ADO.NET的型别绑定

前言

反射(Reflection),虽然是很久以前就已经有的概念,且在微软的C#.NET中已经有做好相关的组件System.Reflection,开发者可以很容易地去应用反射的概念,如果你想做下面的事情的话:

当我们自定义完一个类别(class),你要怎么在执行阶段取得类别的

型别(Type)属性(Attribute)资讯(PropertyInfo、FieldInfo or MemberInfo)是否有挂标籤(CustomAttribute)

或者当我们在Model里面定义完一个方法,你要怎么在执行阶段取得方法的

内容(MethodInfo)参数(MethodInfo.GetGenericArguments)回传值内容(MethodInfo.ReturnParamter)回传值型别(MethodInfo.ReturnType)etc...

只是不知怎么的,待过的公司专案几乎没有用到这个概念,但它真的很好用,搭配泛型可以把很多东西提取出来共用,可以省下非常多的功夫。

应用于ADO.NET

最明显可以写成共用的就是ADO.NET,以前在使用ADO.NET存取资料库的时候,不外乎就是SqlConnection连线之后,透过SqlCommand下指令,再透过SqlDataAdapter的Fill方法,把资料填入DataTable或是用DataReader来读取资料再塞到Model里面。

DataTable与Model的Mapping

DataTable如果要转换成Model List通常做法会是这样。

//传入DataTable物件,回传Model Listpublic List<DataClass> GetModelList(DataTable dt){    var result = new List<DataClass>();    //一笔一笔透过栏位名称与Model绑定    foreach(var row in dt.Rows)    {        var element = new DataClass();        element.PropA = row["PropA"].ToString();        element.PropB = row["PropB"].ToString();        //etc..        result.Add(element);    }    return result;}

相当简单易懂,Datable进来就一个一个绑定到Model里面,非常适合新人来阅读还有撰写,不过写久了就觉得感觉好流水帐,而且element.XXX = row.Column["XXX"].ToString(),这种动作栏位有几个就要重複几次,难道没有更好的做法?有的,请看下方。

public List<DataClass> GetModelList(DataTable dt){    //一行解决    return dt.MapToModelList<DataClass>();}//DataTable与Model List转换//并应用泛型来使所有物件都可以使用这方法public static List<T> MapToModelList<T>(this DataTable dataTable){    var result = new List<T>();    foreach (DataRow dr in dataTable.Rows)    {        result.Add(dr.MapToModel<T>());    }    return result;}//DataRow与Model转换private static T MapToModel<T>(this DataRow dataRow){    //先建立一个预设回传值    var result = Activator.CreateInstance<T>();    //透过Reflection取得型别与属性清单    foreach (var property in typeof(T).GetProperties())    {        //透过Reflection绑定值        property.SetValue(result, dataRow[property.Name].ToString());    }    return result;}

感觉门槛高了一点,但是其实并不难,而且写完之后可以打通你的任督二脉,之后如果有DataTable要转Model List的,只要写一行就好了。

DataReader与Model的Mapping

类似作法也会出现在DataReader与Model List的转换,比较传统的作法会是这样。

//传入DataReader物件,回传Model Listprivate static List<DataClass> GetModelList(DbDataReader dataReader){    var result = new List<DataClass>();    while (dataReader.Read())    {        var element = new DataClass();        element.PropA = dataReader["PropA"].ToString();        element.PropB = dataReader["PropB"].ToString();        //etc...        result.Add(element);    }    return result;}

应用类似的概念,修改成

//DataReader与Model List的转换//并应用泛型来使所有物件都可以使用这方法public List<T> MapToModelList<T>(DbDataReader dataReader){    var result = new List<T>();    while (dataReader.Read())    {        result.Add(dataReader.MapToModel<T>());    }    return result;}//DataReader与Model的转换private static T MapToModel<T>(this DbDataReader dataReader){    //先建立一个预设回传值    var result = Activator.CreateInstance<T>();    //透过Reflection取得型别与属性清单    foreach (var property in typeof(T).GetProperties())    {        //透过Reflection绑定值        property.SetValue(result, dataReader[property.Name]);    }    return result;}

结语

以上两种做法都只是简单实作一下,实际上直接呼叫这两个方法会出现一些例外,例如资料库栏位名称不正确或者值的型态需要转换等等,我有做了一个小小的套件放在Github上,这套件有解决了某些例外情形,例如属性与栏位型别之间的判定以及如果属性与栏位的名称不同,可以透过Column Attribute来设定资料表栏位的名称,希望提供给各位参考参考。
SimpleObjectMapper
应用反射的技巧,就可以省下很多时间来做更有意义的事情,但其实我这样做的初衷很简单,就是,所以懒惰是人类进步的原动力,这个观点真的是对极了。

参考来源

Reflection
SimpleObjectMapper


关于作者: 网站小编

码农网专注IT技术教程资源分享平台,学习资源下载网站,58码农网包含计算机技术、网站程序源码下载、编程技术论坛、互联网资源下载等产品服务,提供原创、优质、完整内容的专业码农交流分享平台。

热门文章