• C#类型反射、晚期绑定、特性编程的使用背景与分析


         任何编程语言的任何特点都是有存在的道理的,C#中有些特点也许我们不求甚解的用过,但是如果知道它的使用背景与原理,使用起来将更加得心应手。本文主要分析的就是C#中的类型反射、晚期绑定、特性编程。阐释为什么要用这些语言特点?

         首先看一下简单项目的需求:程序员开发了很多模块,每个模块对应相应的功能,不同的用户可能需要使用的模块不一样,模块以插件的形式与系统集成,也就是提供给用户一个自定义模块的功能。

         更加形象的比如:一个通用的图书馆里系统中有普通老师模块、有院长模块、有校长模块、有学生模块,这些模块都具有借书的功能(每个模块借书本数不一样);这个通用的系统可能给很多学校使用,每个学校根据自己的需求选择模块。

    对于上面这个需求分析,1、由于这些模块都具有借书的功能,首先想到的是建立一个接口,接口中包含一个借书的函数,所有模块都要实现这个接口。

    2、分别实现这些插件模块,编译成程序集DLL文件。

    3、由于这是一个通用的系统,模块的选择应该由用户决定,因此我们不能预先把所有的模块功能都编译到系统中去(晚期绑定派上用场)。

    4、用户选择一个模块(DLL文件),就相当于要加载一个程序集DLL(动态加载的概念),此时的DLL与用C/C++编写的DLL不一样,它是由微软中间语言IL组成的,里面记录了

        DLL所有信息的元数据。

    5、需要调用具体某个DLL模块中的具体借书函数,这个时候就需要从动态加载的DLL中获取到相应的类,实例化类,调用类的成员函数,这个就需要反射来干了。

    6、有的时候在大型项目中,每个模块可能有不同的子部门来做,因此每个模块应该包好有这些部门的基本信息,这个时候在编写模块的功能时候,就可利用C#中的特性编程了,利用特性可以

         给模块附加上额外的信息,这些信息会被编译到程序集中,同理我们也可以反射出这些信息来。

    下面是一个简单代码的例子:利用了这些特性

    插件接口的定义:

    View Code
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace CommonTypes
    {
        //定义一个接口
        public interface IAppDll
        {
            void DoThing();          
        }
    
        //自定义特性类
        [AttributeUsage(AttributeTargets.Class)]
        public sealed class CarInfoAttribute : System.Attribute 
        {
            public string name{ get; set;}       
        }
    
    }

    根据上面的定义的接口约束,开发第三方的插件

    View Code
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    using System.Windows.Forms;
    using CommonTypes;
    
    namespace CsharpDll
    {
        [CarInfo(name="这是第三方生产的插件")]
        public class CsharpModule:IAppDll
        {
           public void DoThing()//实现接口中的函数
            {
                MessageBox.Show("正在调用的是Csharp插件模块");
            } 
        }
    }

    在窗体程序中调用第三方插件

    View Code
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    
    using System.Reflection;
    using CommonTypes;
    
    namespace WindowsFormsApplication1
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
    
            private void openToolStripMenuItem_Click(object sender, EventArgs e)
            {
                //选择一个插件加载
                OpenFileDialog OFD = new OpenFileDialog();
                if (OFD.ShowDialog() == DialogResult.OK) 
                {
                    if (!LoadModule(OFD.FileName))
                        MessageBox.Show("没有成功加载第三方的插件!");
                
                }
            }
    
            private bool LoadModule(string path) 
            {
                bool FindModule = false;
                Assembly asm = null;
                try
                {
                    //加载指定路径下的程序集
                    asm = Assembly.LoadFrom(path);
                }
                catch (Exception ex) 
                {
                    MessageBox.Show(ex.Message);
                    return FindModule;
                }
                //得到程序集中所有的IAppDll接口兼容的累
                var ClassTypes = from t in asm.GetTypes()
                                 where t.IsClass &&
                                 (t.GetInterface("IAppDll") != null)
                                 select t;
    
                //创建对象,并调用类中的方法
                foreach (Type t in ClassTypes) 
                {
                    FindModule = true;
                    //使用晚期绑定建立类型,强制转换为接口类型
                    IAppDll someApp =(IAppDll)asm.CreateInstance(t.FullName, true);
                    someApp.DoThing();
                    listBox1.Items.Add(t.FullName);
                    //显示插件的相关信息
                    DisplayCarinfo(t);
                }
                return FindModule;
            }
    
            //显示插件的信息
            private void DisplayCarinfo(Type t) 
            {
                var info = from carAtr in t.GetCustomAttributes(false)
                           where (carAtr.GetType() == typeof(CarInfoAttribute))
                           select carAtr;
                //显示特性的属性
                foreach (CarInfoAttribute cia in info) 
                {
                    MessageBox.Show(cia.name);            
                }
            }
        }
    }
  • 相关阅读:
    JavaScript学习(一)
    CSS学习(1)(网页编程)
    学习MVC3(二)——创建自己的第一个网页:实现用户登陆(1)
    C#多态小结——面向对象编程的三大机制之二
    学习网页编程(一)
    开始的2012
    基于jquery的上传插件Uploadify 3.1.1在MVC3中的使用:上传大文件的IO Error问题
    网页编程注意
    基于jquery的上传插件Uploadify 3.1.1在MVC3中的使用
    BackgroundSize
  • 原文地址:https://www.cnblogs.com/guoyuanwei/p/2545397.html
Copyright © 2020-2023  润新知