美文网首页
二刷:反射

二刷:反射

作者: 山猪打不过家猪 | 来源:发表于2022-12-08 13:43 被阅读0次

1.反射

image.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.LibAnimal.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
image.png

相关文章

  • 二刷:反射

    1.反射 1.1 反射的原理 .net 和.net core的反射的類庫是不一樣的;自己寫的程序不要過多的使用反射...

  • reflect.go包学习_之二 指针操作提高反射性能 反射应用

    reflect.go包学习_之二 指针操作提高反射性能 反射应用 反射创建实例 反射信息、反射调用方法、反射修改值...

  • 反射(二)

    反射(二) 通过栗子来更好的理解反射,以及对反射技术进行应用。 首先,整两个model——car.java和Ben...

  • 反射三定律

    反射第一定律:反射可以将interface类型变量转换成反射对象 反射第二定律:反射可以将反射对象还原成inter...

  • 反射学习二——反射

    java高级之反射 一、反射入门 在方法区存在这么一些对象,叫做类对象,他们表述了我们写的所有的类,当我们new对...

  • Java一反射

    目录 一、什么是反射 二、反射的作用和应用场景 三、反射的优缺点 四、使用反射(获取Class对象、获取类的构造方...

  • go基础——反射二(反射使用)

    内容 1 获取接口类型值2 修改接口类型值3 反射调用函数4 反射调用方法5 reflect包api使用 先回顾一...

  • Android 系统复习面试系列(二)反射原理和 Android

    Android 系统复习面试系列(二)反射原理和 Android 类加载核心 反射 什么是反射 指在运行状态中,对...

  • 8 涂层+全部

    涂层可以理解成第二层反射 计算优先级 1 涂层 2 反射 3 折射 4反射 5 散射 ——————————————...

  • Java反射(二)

    类 反射调用一:调用无参构造函数 反射调用二:调用含参构造函数

网友评论

      本文标题:二刷:反射

      本文链接:https://www.haomeiwen.com/subject/makifdtx.html