美文网首页
二刷:反射

二刷:反射

作者: 山猪打不过家猪 | 来源:发表于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

    相关文章

      网友评论

          本文标题:二刷:反射

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