首页 > 代码库 > CLR类型设计之泛型(二)

CLR类型设计之泛型(二)

            在上一篇文章中,介绍了什么是泛型,以及泛型和非泛型的区别,这篇文章主要讲一些泛型的高级用法,泛型方法,泛型泛型接口和泛型委托,协变和逆变泛型类型参数和约束性,泛型的高级用法在平时的业务中用的不多,多用于封装高级方法和一些底层封装,前几天读了一篇文章,如何选择网络上的技术文章,因为现在关于技术的文章可以说非常多,但是时间是有限的,如果花很多时间阅读了一篇文章却没有什么用,岂不是很浪费时间,所以第一步选择自己感兴趣的文章阅读,第二要把阅读过的文章尽可能实现一次,读书万遍不如走上一遍,第三尽量不读翻译性的文章,这里其实我觉得不是所有人都能很轻松的看懂官方文档,所以这点还是仁者见仁,智者见智。为了让文章尽可能的有深度,所以我觉得以后的博文中应该尽可能的贴出的知识模块都有所解释,有所理解。不是在网上复制粘贴以后在给别人看,博文不是笔记,所以要说出自己的见解

          说了这么多,那么就开始务实的甩开膀子做吧!

          泛型方法

             既然讲到了泛型是为了高级封装,那么我们就来封装一个C#中的ORM吧,在封装ORM之前还要有一个SQL帮助类,这个网上有很多,感兴趣的可以直接到网上找一个,C#中封装的ORM最好的Entity FromWork,感兴趣的可以看下源码,我们先看下下面的代码,这是一个典型的泛型方法

技术分享
 1     /// <summary>
 2         /// 查询获得一个实体
 3         /// </summary>
 4         /// <typeparam name="T"></typeparam>
 5         /// <param name="sql"></param>
 6         /// <param name="sqlParameters"></param>  
 7         /// <param name="transaction"></param>
 8         /// <returns></returns>
 9         public static T Get<T>(string sql, IList<SqlParameter> sqlParameters = null, IDbTransaction transaction = null)
10         {
11             DataTable table = SQLServerHelper.Query(sql, sqlParameters, transaction);
12             if (table != null && table.Rows != null && table.Rows.Count > 0)
13             {
14                 DataRow row = table.Rows[0];
15                 return ConvertRowToModel<T>(row, table.Columns);
16             }
17             else
18             {
19                 Type modeType = typeof(T);
20                 return default(T);
21             }
22 
23         }
View Code

            注释已经表明了这是用来获取一个实体的Get<T>()方法中T定义为泛型类型,方法有一个必选参数两个默认参数,string类型的sql语句,默认IList<SqlParameter> sqlParameters继承自IList集合的SQL参数。这是参数化SQL的,每一个SQL语句都应该写成参数化的,还有一个IDbTransaction transaction = null是否开启事务,有了这样三个参数就可以定义一个查询指定SQL语句,是否有Where条件,是否开启事务的方法,方法继续执行,第是一行代码是使用帮助类获得数据,第14行和第15行是将获得数据映射成对应的结构体,我们可以看下 ConvertRowToModel<T>(row, table.Columns)的内部实现

技术分享
  1   public static T ConvertRowToModel<T>(DataRow row, DataColumnCollection columns)
  2         {
  3             Type modeType = typeof(T);
  4             Object model = Activator.CreateInstance(modeType);
  5 
  6             foreach (var p in model.GetType().GetProperties())
  7             {
  8                 var propertyName = p.Name.ToUpper();
  9                 var propertyType = p.PropertyType.Name;
 10                 if (columns.Contains(propertyName))
 11                 {
 12                     var value =http://www.mamicode.com/ row[propertyName];
 13 
 14                     if (propertyType.ToUpper().Contains("STRING"))
 15                     {
 16 
 17                         if (Convert.IsDBNull(value))
 18                         {
 19                             value = http://www.mamicode.com/string.Empty;
 20                         }
 21                         else
 22                         {
 23                             p.SetValue(model, value.ToString(), null);
 24                         }
 25                     }
 26                     else if (propertyType.ToUpper().Contains("INT"))
 27                     {
 28 
 29                         if (Convert.IsDBNull(value))
 30                         {
 31                             value = http://www.mamicode.com/0;
 32                         }
 33 
 34                         p.SetValue(model, Int32.Parse(value.ToString()), null);
 35                     }
 36                     else if (propertyType.ToUpper().Contains("SINGLE"))
 37                     {
 38 
 39                         if (Convert.IsDBNull(value))
 40                         {
 41                             value = http://www.mamicode.com/0.0f;
 42                         }
 43                         p.SetValue(model, Single.Parse(value.ToString()), null);
 44                     }
 45                     else if (propertyType.ToUpper().Contains("DATETIME"))
 46                     {
 47 
 48                         if (Convert.IsDBNull(value))
 49                         {
 50                             value =http://www.mamicode.com/ DateTime.MinValue;
 51                         }
 52                         p.SetValue(model, DateTime.Parse(value.ToString()), null);
 53                     }
 54                     else if (propertyType.ToUpper().Contains("DOUBLE"))
 55                     {
 56 
 57                         if (Convert.IsDBNull(value))
 58                         {
 59                             value = http://www.mamicode.com/0.0d;
 60                         }
 61                         p.SetValue(model, Double.Parse(value.ToString()), null);
 62                     }
 63                     else if (propertyType.ToUpper().Contains("BOOLEAN"))
 64                     {
 65 
 66                         if (Convert.IsDBNull(value))
 67                         {
 68                             value = http://www.mamicode.com/false;
 69                         }
 70                         if (value.GetType() == typeof(Int32))
 71                         {
 72                             p.SetValue(model, Int32.Parse(value.ToString()) == 1, null);
 73 
 74                         }
 75                         else if (value.GetType() == typeof(String))
 76                         {
 77                             p.SetValue(model, Boolean.Parse(value.ToString()), null);
 78                         }
 79                         else if (value.GetType() == typeof(Boolean))
 80                         {
 81                             p.SetValue(model, (Boolean)(value), null);
 82                         }
 83 
 84                     }
 85                     else if (p.PropertyType.IsEnum)//Enum 
 86                     {
 87                         if (Convert.IsDBNull(value) || string.IsNullOrEmpty(value.ToString()))
 88                         {
 89                             value = http://www.mamicode.com/"0";
 90                         }
 91 
 92                         p.SetValue(model, int.Parse(value.ToString()), null);
 93                     }
 94                     else if (propertyType.ToUpper().Contains("DECIMAL"))
 95                     {
 96 
 97                         if (Convert.IsDBNull(value))
 98                         {
 99                             value = http://www.mamicode.com/0.0f;
100                         }
101                         p.SetValue(model, Decimal.Parse(value.ToString()), null);
102                     }
103 
104                 }
105             }
106             return (T)model;
107         }
View Code

         这个方法有点长,但实际上很好理解,并且这个方法也是一个泛型方法,其中的关键点在于他会把所有的字段类型转换成基础的元类型,转换成int,string这些最终会在返回给Get<T>()方法,这样就完成了实体的映射,那么有了上面两个方法,就可以编写简单的ORM了,如果是增删查改的话,就改变其中的逻辑,获得返回的影响行数就可以了,那么如何调用这个ORM呢,封装后最主要的是使用。可以用如下方法直接调用

技术分享
 1     public static Student Getmodel(long id) {
 2             StringBuilder sql = new StringBuilder();
 3             List<SqlParameter> args = new List<SqlParameter>();
 4             //根据学生id获取学生信息
 5             sql.Append("select * from student where id=@id");
 6             //id参数化后赋值
 7             args.Add(new SqlParameter("@id", id));
 8             //调用封装ORM所在的CommonDao类  调用刚才的Get方法  
 9             //映射类Student,就会返回和Student类相符合的数据库字段内容
10             return CommonDao.Get<Student>(sql.ToString(), args);
11         }
View Code

是不是就简单了很多呢。当然你也可以封装的更深一些,这里还是在传递sql语句,如果你喜欢Entitie fromwork那种方式,可以把Sql语句也作为固定的写法,只传递where条件后面的参数就可以了,可以看到泛型方法很有用处

        但是有的时候定义了泛型方法,却希望他只能用于某一种特定的类型,上述的例子可以用于所有泛型类型,但是如果我要封装的不是底层,只是某一个高级方法,只允许某一种类型使用这个方法,那么该如何做呢?可以使用泛型约束

        泛型约束

技术分享
 1  public static T WhereGet<T>(string sql, IList<SqlParameter> sqlParameters = null, IDbTransaction transaction = null)
 2             where T:IList<T>
 3         {
 4             DataTable table = SQLServerHelper.Query(sql, sqlParameters, transaction);
 5             if (table != null && table.Rows != null && table.Rows.Count > 0)
 6             {
 7                 DataRow row = table.Rows[0];
 8                 return ConvertRowToModel<T>(row, table.Columns);
 9             }
10             else
11             {
12                 Type modeType = typeof(T);
13                 return default(T);
14             }
15 
16         }
View Code

 

CLR类型设计之泛型(二)