反射解决了什么问题

反射解决了什么问题及应用场景

反射总结目录

上篇介绍了什么是反射以及FCl中反射的实现,这篇我们来讨进一步讨论反射解决的问题及其应用场景。

在软件开发的过程中我们经常遇见一些相同的问题,比如访问数据库,我们知道数据库的种类繁多,每家数据库供应商都提供了不通的API实现,这就决定我们在软件开发过程中就需要考虑使用的是哪家的数据库他们的API又是什么样子的,这也就产生了依赖关系。
那么问题来了,我们能不能实现一种办法来解决这种依赖关系?

下面列举一个例子:

var dbProvider = ""; //mssql,mysql,sqlite
IDbConnection conn = null;
switch (dbProvider)
{
    case "mssql":
        conn =new SqlConnction("数据库链接串");
        break;
    case "mysql":
        conn = new MySqlConnction("数据库链接串");
        break;
    case "sqlite":
        conn = new SqliteConnction("数据链接串");
        break;  
}
conn.Open();

上面的代码,我们访问了三种数据库,通过工厂方法模式实现了数据库的选择,如果我们只使用这三种数据库,那么这段代码没有什么问题。
如果现在有需求要加入对pgsql数据库的支持,我们需要怎么办呢?有一种实现,我们修改代码,添加case返回pg的IDBConnection实现并重新编译代码然后发布。这看起来没有什么难处,不就是添加几行代码做几次编译发布吗?没有什么大不了的!如果要删除某一个数据库的支持呢。。。。。。
这个问题看起来简单,但类似的业务场景有很多,如果都这样解决,那只是把脑力劳动变成了体力劳动。(程序员都很懒,起码我是这样)。

下面是我的改进方案:

通过参数化的配置实现了类库的动态加载,反射查到需要的类型并使用。
var dbConfig = new
{
    Name = "mssql", //mssql,mysql,sqlite,pgsql,oracle,access等数据库
    ConnName = "SqlConnection",
    ConnStr = "数据库链接字符串"
};

var connType = Assembly.LoadFile($"*/{dbConfig.Name}.dll").GetType(dbConfig.ConnName);
IDbConnection  conn =(IDbConnection)Activator.CreateInstance(connType, dbConfig.ConnStr);
conn.Open();
这不是一个能说明反射的好例子,因为我们不可能同时使用多种数据库,而且数据库的切换也不可能频繁,这个例子只是为了说明怎么通过反射来实现一些功能,希望各位观众不要被这个例子误导。

反射解决了什么问题?

在面向对象的世界中如果你不懂得一点反射知识是很难做到低耦合的。比如现在IOC框架本质就是利用反射技术来实现解耦的效果。
  1. 动态加载,按需加载程序集
  2. 解耦
  3. 提高组件的复用性
  4. 解决了最主要的问题就是装13

反射的应用场景

  1. Visual Studio中开发C#时通过反射实现智能感知效果
  2. IOC是反射的最好应用

我在项目中怎么使用反射

使用反射实现数据访问层的抽象。
数据访问层的接口实现
public interface IBaseDAO { }

public interface IClientDAO : IBaseDAO
{
    List<int> GetClientIds();

    ClientEntity GetClientInfo(int cId);
}

//反射获取接口的实现
public class DAOHelper
{
    public static Dictionary<Type, Type> daoDict = new Dictionary<Type, Type>();

    public static T Create<T>() where T : IBaseDAO
    {

        if (daoDict.ContainsKey(typeof(T)))
        {
            Type t = daoDict[typeof(T)];
            return (T)Activator.CreateInstance(t);
        }

        var assembly=Assembly.Load("ReflectionAssembly");
        var type = assembly.ExportedTypes.FirstOrDefault(item => item.GetInterface(typeof(T).FullName) == typeof(T));
        if (type == null)
        {
            throw new NotImplementedException($"{typeof(T).FullName}接口未实现");
        }
        //演示,没有添加lock
        daoDict.Add(typeof(T), type);
        return (T)Activator.CreateInstance(type);
    }
}
实现数据访问层接口
namespace ReflectionAssembly
{
    public class ClientDAO : IClientDAO
    {
        public List<int> GetClientIds()
        {
            return new List<int> { 1, 2, 3, 4 };
        }

        public ClientEntity GetClientInfo(int cId)
        {
            return new ClientEntity();
        }
    }
}
数据实体层
public class ClientEntity
{
}
业务层
var clientDAO=DAOHelper.Create<IClientDAO>();
clientDAO.GetClientIds();
clientDAO.GetClientInfo(1);
上面这段代码就是我在项目中通过反射实现,处于演示的目的,很多情况都没有列出,比如多线程下锁的处理、如何加速等。

小结

上面两个例子演示了如何在项目中使用反射,并列举了反射可以帮助我们解决什么问题,有些概念可能模糊不清或者不是很贴切,希望阅读本文章的兄弟不吝赐教。
上一篇:1.数据类型


下一篇:处理使用top提示terminal is not big enough