C#反射的Assembly的简单应用

  反射(Reflection)是.NET中的重要机制,通过反射,可以在运行时获得.NET中每一个类型(包括类、结构、委托、接口和枚举等)的成员,包括方法、属性、事件,以及构造函数等。还可以获得每个成员的名称、限定符和参数等。有了反射,即可对每一个类型了如指掌。如果获得了构造函数的信息,即可直接创建对象,即使这个对象的类型在编译时还不知道。

Assembly就是反应反射的一种应用,它定义和加载程序集,加载在程序集清单中列出模块,以及从此程序集中查找类型并创建该类型的实例。简单地说就是,使用Assembly在程序中你不用事先写比如下面的东西了:

PersonClass person = new PersonClass();
person.Method();

 你只要知道PersonClass这个类的程序集,命名空间和类名直接使用反射就可以使用。你只需要这样写:

PersonClass person;
person = 
person = (PersonClass)(Assembly.Load("程序集").CreateInstance("命名空间.类名", false, BindingFlags.Default, null, args, null, null));
person.Method();

下面用一个小例子来看看Assembly应用的方便性。

需求:有几种文件格式,后缀分别是.One,.Two,.Three,... 有很多种,后续还可能增加。这些文件的格式都不一样,也就是说读取方式就不一样。那么根据传入的文件后缀和路径读出文件的内容。

实现:

这种需求的特点是,根据选择做不同的处理,但是都是出的一种结果,那么可以使用简单工厂模式来完成。

读取文件有一个父类FileSuper,内部如下:

using System;
using System.Collections.Generic;
using System.Text;

namespace reflect
{
    public abstract class FileSuper//获取不同后缀名文件的内容
    {
       public abstract string GetFileContext(string fileFullPath);
    }
}

分别有MyFileOne,MyFileTwo,MyFileThree等,继承FileSuper,如下:

using System;
using System.Collections.Generic;
using System.Text;

namespace reflect
{
    public class MyFileOne : FileSuper
    {
        public override string GetFileContext(string fileFullPath)
        {
            return "One类型文件的内容";
        }
    }
}
using System;
using System.Collections.Generic;
using System.Text;

namespace reflect
{
    public class MyFileTwo : FileSuper
    {
        public override string GetFileContext(string fileFullPath)
        {
            return "Two类型文件的内容";
        }
    }
}
using System;
using System.Collections.Generic;
using System.Text;

namespace reflect
{
    public class MyFileThree : FileSuper
    {
        public override string GetFileContext(string fileFullPath)
        {
            return "Three类型文件的内容";
        }
    }
}

一个工厂类根据后缀名决定实例化哪个类:

using System;
using System.Collections.Generic;
using System.Text;

namespace reflect
{
    public class OperationFile
    {
        static FileSuper fileSuper = null;

        public static string GetStringByFile(string fileFullPath, string extendName)
        {
            switch (extendName)
            {
                case "One":

                    fileSuper = new MyFileOne();

                    break;

                case "Two":

                    fileSuper = new MyFileTwo();

                    break;

                case "Three":

                    fileSuper = new MyFileThree();

                    break;
            }

            if (fileSuper != null)
            {
                return fileSuper.GetFileContext(fileFullPath);
            }

            return "没有指定的类型";
        }
    }
}

客户端调用,显示结果:

using System;
using System.Collections.Generic;
using System.Text;

namespace reflect
{
    public class Program
    {
        static void Main(string[] args)
        {
            string fileContext = OperationFile.GetStringByFile("路径", "One");

            Console.WriteLine(fileContext);

            Console.ReadLine();
        }
    }
}

这样解决了这个需求,前面在读书笔记6:工厂方法模式 中提到了这种方式的缺点,就是不符合开放封闭原则,那么如何改进了,除了工厂方法模式,我们可以使用Assembly。使用它之前,要先写一个类和一个配置文件。

先看配置文件:MyFile.xml

<?xml version="1.0" encoding="utf-8" ?>
<FileExtendName>
  <extend>
    <name>One</name>
    <class>MyFileOne</class>
  </extend>
  <extend>
    <name>Two</name>
    <class>MyFileTwo</class>
  </extend>
  <extend>
    <name>Three</name>
    <class>MyFileThree</class>
  </extend>
</FileExtendName>

是后缀名和类名的对应。

另一个读取配置文件的类ExtendNameDataTable。

using System;
using System.Collections.Generic;
using System.Text;
using System.Data;

namespace reflect
{
    public class ExtendNameDataTable
    {
        private static DataSet extendDataSet;

        public static DataSet ExtendDataSet
        {
            get
            {
                if (extendDataSet == null)
                {
                    extendDataSet = new DataSet();

                    extendDataSet.ReadXml(@"F:\MyFile.xml");
                }
                return extendDataSet;
            }
        }
    }
}

做好这两个准备后,只需修改OperationFile工厂类,其余都不用修改。使用Assembly来根据配置文件,自动按照传入的后缀名加载类,并且实例化,修改后的OperationFile如下:

using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Reflection;

namespace reflect
{
    public class OperationFile
    {

        public static string GetStringByFile(string fileFullPath, string extendName)
        {

            DataRow dr = ((DataRow[])ExtendNameDataTable.ExtendDataSet.Tables[0].Select("name='" + extendName + "'"))[0];

            object[] args = null;

            FileSuper fileSuper;

            fileSuper = (FileSuper)(Assembly.Load("reflect").CreateInstance(

                "reflect." + dr["class"].ToString(), false, BindingFlags.Default, null, args, null, null));

            return fileSuper.GetFileContext(fileFullPath);

        }
    }
}

客户端调用不变输出结果:

我们看到,这样一来,如果有了新的文件结构,只需要再写一个MyFileFour类继承自FileSuper;然后再在MyFile.xml中增加相应的对应关系就可以了,避免了要修改OperationFile的case分支,符合开放封闭原则。

    当然Assembly这么好使用,也不是所有情况下都能用的,当在循环中碰到了这种情况,那么还是使用简单工厂模式或者工厂方法模式吧,因为再循环中使用Assembly实例化会导致性能下降。

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值