反射

反射是.net中的重要机制。通过反射,可以在运行时获得.net中每一个类型(包括类、结构、委托和枚举等)成员,包括方法、属性、事件,以及构造函数等。还可以获得每个成员的名称、限定符和参数等。

有了反射,即可对每一个类型了如指掌。如果获得了构造函数的信息,即可直接创建对象,即使这个对象的类型在编译时还不知道。

反射的用途:

(1)使用Assembly定义和加载程序集,加载在程序集清单中列出模块,以及从此程序集中查找类型并创建该类型的实例。

(2)使用Module了解包含模块的程序集以及模块中的类等,还可以获取在模块上定义的所有全局方法或其他特定的非全局方法。

(3)使用ConstructorInfo了解构造函数的名称、参数、访问修饰符(如pulic 或private)和实现详细信息(如abstract或virtual)等。使用Type的GetConstructors或GetConstructor方法来调用特定的构造函数。

(4)使用MethodInfo了解方法的名称、返回类型、参数、访问修饰符(如pulic 或private)和实现详细信息(如abstract或virtual)等。使用Type的GetMethods或GetMethod方法来调用特定的方法。

(5)使用FiedInfo了解字段的名称、访问修饰符(如public或private)和实现详细信息(如static)等,并获取或设置字段值。

(6)使用EventInfo了解事件的名称、事件处理程序数据类型、自定义属性、声明类型和反射类型等,添加或移除事件处理程序。

(7)使用PropertyInfo了解属性的名称、数据类型、声明类型、反射类型和只读或可写状态等,获取或设置属性值。

(8)使用ParameterInfo了解参数的名称、数据类型、是输入参数还是输出参数,以及参数在方法签名中的位置等。

在设计模式中,用到反射技术,可以简化工厂的实现,极大地简化对象的生成,可以精化模式:

(1)工厂方法:通过反射可以将需要实现的子类名称传递给工厂方法,这样无须在子类中实现类的实例化。

(2)抽象工厂:使用反射可以减少抽象工厂的子类,简化工厂代码的复杂程度。

(3)命令模式:可以采用命令的类型名称作为参数直接获得命令的实例,并且可以动态执行命令。

(4)享元模式:采用反射技术实例化享元可以简化享元工厂。

下面看一下反射的具体代码:

先对比一下常规写法和反射的写法

// 常规的写法
IUser result=new SqlserverUser();

 

//反射的写法
using System.Reflection;//引用命名空间
IUser result=(IUser)Assembly.Load("抽象工厂模式").CreateInstance("抽象工厂模式.SqlserverUser")
//第一个抽象工厂模式是当前“程序集”的名称
//第二个是当前命名空间的名称
//后面是要实例化的“类名”

通过上面两种写法的对比,我们可以看出常规方法是写明了要实例化SqlserverUser对象。反射的写法可以用变量来处理,根据需要进行更换。反射可以利用字符串来实例化对象。

下面我们用一个具体的类来看一下常规的写法:

class DataAccess
    { 
        private static readonly string db="Sqlserver";//数据库名称
        //private static readonly string db="Access";
        public static IUser CreateUser()
        {
            IUser result = null;
            switch (db)//由于db的实现设置,多疑此处可以根据选择,实例化出相应的对象
            { 
                case "Sqlserver":
                    result = new sqlserverUser();
                    break;
                case "Access":
                    result = new AccessUser();
                    break;
            }
            return result;
        }
        public static IDepartment CreateUser()
        {
            IDepartment result = null;
            switch (db)
            { 
                case "Sqlserver":
                    result = new sqlserverUser();
                    break;
                case "Access":
                    result = new AccessUser();
                    break;
            }
            return result;
    }

我们可以看出上面的代码switch判断会给我们带来麻烦。当我们再增加一个Oracle数据库访问的时候,我们只能去改变switch语句,违反程序设计的对修改封闭的原则。下面我们再看一下反射的写法:

using System.Reflcetion;//引用反射
class DataAccess
    {
        private static readonly string AssemblyName="抽象工厂模式";//程序集名称
        private static readonly string db="Sqlserver";//数据库名称,可以替换成Access

        public static IUser CreateUser()
        {
            string ClassName=AssemblyName+"."+db+"User";
            return (IUser )Assembly.Load (AssemblyName ).CreateInstance (ClassName );
        }
        public static IDepartment  CreateDepartment()
        {
            string ClassName=AssemblyName+"."+db+"User";
            return (IDepartment)Assembly.Load (AssemblyName ).CreateInstance (ClassName );
        }
    }

这样,我们就将程序由编译时运行时。由于‘CreateInstance("抽象工厂模式.SqlserverUser")’中的字符串是可以写成变量的,而变量的值到底是SQL Server,还是Access,完全可以由事先的那个db变量来决定。所以就省去了用switch判断的麻烦。
这样修改后已经很好了,但是在更换数据库访问时,我们要是要去改程序重编译,本例中就该修改db变量的值。这样还是不够完美。为了达到正真符合开放-封闭原则。我们可以再利用配置文件来解决更改DataAccess的问题。我们可以读文件给DB字符串赋值,在配置文件中写明是Sqlserver还是Access。应用反射+配置文件+抽象工厂模式解决数据库访问时的可维护、可扩展的问题。

 

 

转载于:https://www.cnblogs.com/liu765023051/archive/2011/11/10/2813633.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值