1.反射
![](https://img.haomeiwen.com/i14814834/27ec9671e4cc667c.png)
namespace orderDemo
{
class Program
{
static void Main(string[] args)
{
var driver1 = new Driver(new HeavyTank());
var driver2= new Driver(new RaceCar());
driver1.drive();
driver2.drive();
Console.ReadKey();
}
}
class Driver
{
private IVehichle _vehicle;
//只可以开车不能开坦克
public Driver(IVehichle vehichle)
{
this._vehicle = vehichle;
}
public void drive()
{
this._vehicle.Run();
}
}
interface IWeapon
{
void Fire();
}
public interface IVehichle
{
void Run();
}
public class Car : IVehichle
{
public void Run()
{
Console.WriteLine("Car is running...");
}
}
public class RaceCar : IVehichle
{
public void Run()
{
Console.WriteLine("RaceCar is running...");
}
}
interface ITank:IVehichle,IWeapon
{
void Fire();
void Run();
}
class LightTank : ITank
{
public void Fire()
{
Console.WriteLine("Boom.....");
}
public void Run()
{
Console.WriteLine("LightTank is running...");
}
}
class MediumTank : ITank
{
public void Fire()
{
Console.WriteLine("Big Boom.....");
}
public void Run()
{
Console.WriteLine("MediumTank is running...");
}
}
class HeavyTank : ITank
{
public void Fire()
{
Console.WriteLine("Biggggggggggggggg Boom.....");
}
public void Run()
{
Console.WriteLine("HeavyTank is running...");
}
}
}
1.1 反射的原理
.net 和.net core的反射的類庫是不一樣的;自己寫的程序不要過多的使用反射機制!
- 使用反射調用重型坦克的方法
class Program
{
static void Main(string[] args)
{
//静态类型声明
ITank tank1 = new HeavyTank();
var t = tank1.GetType();
object o = Activator.CreateInstance(t);
MethodInfo fireMi = t.GetMethod("Fire");
MethodInfo runMi = t.GetMethod("Run");
fireMi.Invoke(o, null);
runMi.Invoke(o, null);
Console.ReadKey();
}
}
但是,這種方式在我們開發中很少使用,一般我們使用的都是封裝好的反射
1.2 反射的第一個用途(依賴注入)
依賴注入理解:用註冊的類型創建的實例注入到其構造器里;
依賴注入作用:一個程序有很多的代碼,經常使用的都是固定的類,但是有一天程序添加了新的類,或者需要將以前的類換成一個新的版本的類,那麼就需要去找到所有的代碼去改,但是呢又要保留一部分的舊的類,那麼就是用依賴注入就可以了
- 還是坦克的例子
class Program
{
static void Main(string[] args)
{
var sc = new ServiceCollection();
//1.注册,程序启东时
sc.AddScoped(typeof(ITank), typeof(HeavyTank));
var sp = sc.BuildServiceProvider();
//2.使用
ITank tank = sp.GetService<ITank>();
tank.Fire();
tank.Run();
Console.ReadKey();
}
}
>>>
Biggggggggggggggg Boom.....
HeavyTank is running...
- 如果不想是用HeavyTank,只需要更換註冊時的類即可:
class Program
{
static void Main(string[] args)
{
var sc = new ServiceCollection();
//1.注册,程序启东时
sc.AddScoped(typeof(ITank), typeof(LightTank));
var sp = sc.BuildServiceProvider();
//2.使用
ITank tank = sp.GetService<ITank>();
tank.Fire();
tank.Run();
Console.ReadKey();
}
}
>>>
Boom.....
LightTank is running...
- 除了註冊具體的類,還可以註冊接口
class Program
{
static void Main(string[] args)
{
var sc = new ServiceCollection();
//1.注册,程序启东时
sc.AddScoped(typeof(IVehichle), typeof(Car));
//sc.AddScoped(typeof(IVehichle), typeof(HeavyTank));
sc.AddScoped<Driver>();
var sp = sc.BuildServiceProvider();
var driver1 = sp.GetService<Driver>();
driver1.Drive();
Console.ReadKey();
}
}
>>>
Car is running...
//HeavyTank is running...
1.3 反射的第二個通途(解耦)
插件式編程
背景:一個嬰兒車的廠商,嬰兒車有小麵板,不同的按鈕,按車上的按鈕的數字,數字上的畫面,就會根據數字叫
使用纯反射来实现
-
创建主程序ConsoleApp3,并且在该文件中创建一个Animals的文件夹
image.png
- 主程序入口
Program.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Loader;
namespace ConsoleApp3
{
class Program
{
static void Main(string[] args)
{
var folder = Path.Combine(Environment.CurrentDirectory, "Animals");
//获取他所在的文件夹
var files = Directory.GetFiles(folder);
var animalTypes = new List<Type>();
foreach (var file in files)
{
var assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(file);
var types = assembly.GetTypes();
foreach (var t in types)
{
if (t.GetMethod("Voice")!=null)
{
animalTypes.Add(t);
}
}
}
while (true)
{
for (int i = 0; i < animalTypes.Count; i++)
{
Console.WriteLine($"{i + 1}.{animalTypes[i].Name}");
}
Console.WriteLine("============");
Console.WriteLine("Please choose animiam:");
int index = int.Parse(Console.ReadLine());
if (index > animalTypes.Count || index < 1)
{
Console.WriteLine("No such animal.Try again");
continue;
}
Console.WriteLine("How many times?");
int times = int.Parse(Console.ReadLine());
var t = animalTypes[index - 1];
var m = t.GetMethod("Voice");
var o = Activator.CreateInstance(t);
m.Invoke(o, new object[] { times });
}
}
}
}
- 模拟协同开发,不同的电脑创建类库
Animal.Lib
和Animal.Lib2
image.png
using System;
using System.Collections.Generic;
using System.Text;
namespace Animal.Lib2
{
public class Cow
{
public void Voice(int times)
{
for (int i = 0; i < times; i++)
{
Console.WriteLine("niu shen me niu ");
}
}
}
}
-
将上面的不同类库的dll文件复制到animals下,模拟开发完成
image.png
-
运行主程序
image.png
注意:上面方法是纯反射,但是会出现一个问题是,协同开发的程序的 方法名,不能出现错误,必须严格按照主程序,这样使得开发的难度增加
使用SDK文件中的接口,控制开发
- 创建
IAnimal.cs
接口
using System;
using System.Collections.Generic;
using System.Text;
namespace EasyStroller.SDK
{
public interface IAnimal
{
void Voice(int times);
}
}
- 创建未完成
UnifinishedAttribute.cs
using System;
using System.Collections.Generic;
using System.Text;
namespace EasyStroller.SDK
{
public class UnfinishedAttribute:Attribute
{
}
}
-
将sdk引用到所有需要开发的项目中,规范接口,这样主体程序就不需要每次判断里面的方法了,而是只需要判断是否实现了接口
过滤未完成的方法和判断接口
image.png
![](https://img.haomeiwen.com/i14814834/11f2bf31e81b1197.png)
网友评论