最近做项目时,用到了一点反射处理,下面简单聊一下什么是反射,及反射的使用场景,场景很重要,没有场景,很难深入了解一个技术点。反射是什么,这种在我看来比较高大上的概念就先不聊了,大家在网上搜索一下也很多,我们直接按照需求走一遍。
在ORM处理里,也就是数据库和Model关联时,假设Student表里有StudentID,SName,SClass字段,对应一个StuModel,具备同样的字段,我们怎么处理表和Model的映射关系呢。
※注:我们这里不连接真实的数据库了,用DataTable模拟数据库表。
下面的代码出现了。
Main处理:
using System;
using System.Collections.Generic;
using System.Data;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
Utils du = new Utils();
DataTable dt = du.GetDBData();
List<StuModel> lst = du.TableToStudent(dt);
du.PrintStudent(lst);
Console.Read();
}
}
}
Utils处理:
using System;
using System.Collections.Generic;
using System.Data;
namespace ConsoleApp1
{
class Utils
{
public DataTable GetDBData()
{
DataTable dt = new DataTable();
DataRow dr;
dt.Columns.Add("StudentID");
dt.Columns.Add("SName");
dt.Columns.Add("SClass");
for (int i = 0; i < 10; i++)
{
dr = dt.NewRow();
dr["StudentID"] = (i + 1).ToString();
dr["SName"] = i.ToString() + "AAA";
dr["SClass"] = ((i + 1) % 7).ToString();
dt.Rows.Add(dr);
}
return dt;
}
public List<StuModel> TableToStudent(DataTable dt)
{
List<StuModel> lst = new List<StuModel>();
StuModel s;
foreach (DataRow dr in dt.Rows)
{
s = new StuModel();
s.StudentID = dr["StudentID"].ToString();
s.SName = dr["SName"].ToString();
s.SClass = dr["SClass"].ToString();
lst.Add(s);
}
return lst;
}
public void PrintStudent(List<StuModel> lst)
{
foreach (StuModel m in lst)
{
Console.WriteLine(m.StudentID + ":" + m.SName + ":" + m.SClass);
}
}
}
}
Model类:
namespace ConsoleApp1
{
class StuModel
{
public string StudentID { get; set; }
public string SName { get; set; }
public string SClass { get; set; }
}
}
貌似还可以,模块化了,代码也没有揉做一团。后来项目经理发话了,表加一个字段,SAge,码农们就动起来了,几乎时全盘改动,项目经理再加一个SGender,S。。。。,结局可能有两个,项目经理住院了,或者码农辞职了。。。
那么,能不能不让项目经理挨打,也别让员工辞职呢。有!
看下面一版写法:
Utils处理:
using System;
using System.Collections.Generic;
using System.Data;
using System.Reflection;
namespace ConsoleApp1
{
class Utils
{
public DataTable GetDBData()
{
DataTable dt = new DataTable();
DataRow dr;
dt.Columns.Add("StudentID");
dt.Columns.Add("SName");
dt.Columns.Add("SClass");
dt.Columns.Add("SAge");
for (int i = 0; i < 10; i++)
{
dr = dt.NewRow();
dr["StudentID"] = (i + 1).ToString();
dr["SName"] = i.ToString() + "AAA";
dr["SClass"] = ((i + 1) % 7).ToString();
dr["SAge"] = i + 10;
dt.Rows.Add(dr);
}
return dt;
}
public List<StuModel> TableToStudent(DataTable dt)
{
List<StuModel> lst = new List<StuModel>();
StuModel s ;
foreach (DataRow dr in dt.Rows)
{
s = new StuModel();
Type t = s.GetType();
foreach (PropertyInfo p in t.GetProperties())
{
p.SetValue(s, dr[p.Name].ToString());
}
lst.Add(s);
}
return lst;
}
public List<string> PrintStudent(List<StuModel> listStu)
{
string str;
List<string> lst = new List<string>();
foreach (StuModel m in listStu)
{
str = string.Empty;
Type t = m.GetType();
foreach (PropertyInfo p in t.GetProperties())
{
str += p.GetValue(m) + ":";//为了简化代码,最后的:我们不处理了。
}
lst.Add(str);
}
return lst;
}
}
}
※注:StuModel里加一个SAge属性
public string SAge { get; set; }
按照这一版本写法,我们只需要保证Model和数据库的表字段完全一致就好了,我们把表数据转换成实体类之后的业务代码不用动,或者改动范围很小。减少改修时的规模和问题发生几率。
反射其中一个用途就是运行时动态获取对象信息,不用反射,大多时候我们也能完成需求,用反射的的目的是提高代码的复用率,在需求变更时不要全盘修改。