步步为营-32-反射实例-计算器
说明:设计模式-简单工厂(参考步步为营-09随笔),反射
1 添加窗体应用程序,做好UI界面.这里不添加按钮,按钮通过文档自动创建
2 添加用于运算的父类,但是为了实现反射,需要将其放在类库中,故先加类库ProOperation,
2.1 分析父类,
首先定义成公共抽象类,方便子类实现,
需要两个属性(FirstNumber和SecondNumber),
还需要一个属性运算符Operator,只需要get方法
需要一个方法获得结果GetResult和一个含有两个参数的构造方法
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ProOperation { public abstract class Operation { public Operation(double number1, double number2) { this.FirstNumber = number1; this.SecondNumber = number2; } public double FirstNumber { get; set; } public double SecondNumber { get; set; } public abstract string Operator { get; } public abstract double GetResult(); } }
3 同理子类ProAdd类库和Add子类
3.1 添加引用导入命名空间using ProOperation;
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using ProOperation; namespace ProAdd { public class Add:Operation { public Add(double a, double b) : base(a,b) { } public override string Operator { get { return "+"; } } public override double GetResult() { return this.FirstNumber + this.SecondNumber; } } }
3.2 在窗体应用程序的bin/debug目录下,添加Plug文件夹,需要将ProAdd.dll文件复制到该文件下
4 创建工厂类
4.1 添加引用导入命名空间using ProOperation;using System.Reflection;using System.IO;
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using ProOperation; using System.Reflection; using System.IO; namespace ProFactory { public class Factory { public static Operation GetOper(string operType,double n1,double n2) { Operation oper = null; //01-动态获取程序集 //01-a 获取程序集的目录 string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Plug");//此时Plug目录中有很多类型的文件如.dll,.xml等 //01-b ,所以进一步筛选===获得所有程序集文件的全路径 String[] files = Directory.GetFiles(path, "*.dll");//此时 数组中可能包含{Add.dll,Sub,dll,Mul.dll}等 //02-加载程序集 foreach (var item in files) { //02-a-加载程序集 Assembly ass = Assembly.LoadFile(item);//此时假设是Add.dll 其中可能包含多个类{A.cs,Add.cs,B.cs}等 //02-b ,所以进一步筛选===获得所有程序集文件中的类文件 Type[] types = ass.GetExportedTypes(); foreach (var dllType in types) { //判断当前对象是否符合要求 if (dllType.IsSubclassOf(typeof(Operation))&&!dllType.IsAbstract) { //03-a-创建子类对象,交给父类对象 oper = (Operation)Activator.CreateInstance(dllType, n1, n2);//此时假设是Add.dll 其中可能是{A.cs,Add.cs,B.cs}创建的对象 //03-b-对创建的子类对象进一步筛选 if (operType == oper.Operator)//operType 是传入的字符串"+,-,*,/" 而oper.Operator是类Operation中的运算符属性 { return oper; } } } } return oper; } } }
5 回过头来完善窗体应用程序
5.1 在bin/debug目录下添加文本文件Config.txt,文件内容如下
5.2 添加引用using ProOperation;using ProFactory;
5.3 代码
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using ProOperation; using ProFactory; namespace ProCalculator { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { //1 首先读取配置文件 string[] lines = File.ReadAllLines("Config.txt"); //2 自动创建按钮 //2-a设置按钮初始位置 int x = 100; int y = 222; foreach (string item in lines) { //2-b 遍历结合创建按钮 Button btn = new Button(); btn.Location = new Point(x,y); x =x + 80; btn.Text = item; btn.Click += btn_Click;//添加事件 this.Controls.Add(btn);//添加到窗体上 } } private void btn_Click(object sender, EventArgs e) { Button btn = sender as Button; double n1 ,n2; if (double.TryParse(txtNumber1.Text, out n1) && double.TryParse(txtNumber2.Text, out n2)) { //获得简单工厂类提供的父类对象 Operation oper = Factory.GetOper(btn.Text,n1,n2); lblResult.Text = oper.GetResult().ToString(); } } } }
6 完善*和/
完整代码在对应的百度网盘目录下