C#经验积累_02.接口与反射的在项目中的使用心得

02.接口与反射的在项目中的使用心得

一、简要解释
接口(Interface):
命名为I开头,用于实现面向对象编程中的多态特性,有利于程序的解耦
反射(Reflection):
可以根据内存中的类型参数动态的创建对应类型的实例,并访问其字段、属性及方法等
二、使用实例
接口实现多态:

  class Program
    {
        static void Main(string[] args)
        {
            Ifactory ifactory = new CarFactory();//使用接口变量对实现接口的实例进行装箱
            Console.WriteLine(ifactory.ProductInfo());//打印汽车工厂产品信息
            ifactory = new FoodFactory();
            Console.WriteLine(ifactory.ProductInfo());//打印食品工厂产品信息
            Console.ReadLine();
        }
    }

    /// <summary>
    /// 工厂接口
    /// </summary>
    interface Ifactory
    {
        string ProductInfo();
    }
    /// <summary>
    /// 实现工厂接口的汽车工厂类
    /// </summary>
    class CarFactory: Ifactory
    {
        public string ProductInfo()
        {
            return "汽车工厂生产的产品是各种汽车";
        }
    }
    /// <summary>
    /// 实现工厂接口的食品工厂类
    /// </summary>
    class FoodFactory : Ifactory
    {
        public string ProductInfo()
        {
            return "食品工厂生产的产品是各种食品";
        }
    }

使用接口及反射实现模块化(外挂式)编程和调用:
步骤A,创建接口项目文件生成接口dll文件

  public interface ICar//接口
    {
        void Run(int run);
    }
  public class UnfinishedAttribute:Attribute//在接口项目中添加一个UnfinishedAttribute(类名可以自由命名)类并继承Attribute,在实现接口的方法中可以使用 [Unfinished]标识来标识未完成的接口实现
    {
    }
步骤B,创建ICar接口的实现类并生成对应的dll文件,并将dll文件放入到指定的文件夹内
//实现接口Car类
 public class Car : ICar
    {
        public void Run(int run)
        {
            Console.WriteLine($"Car Run {run}!");
        }
    }
  //实现接口Bus类
    public class Bus : ICar
    {
        public void Run(int run)
        {
            Console.WriteLine($"Bus Run {run}!");
        }
   }
   //实现接口Tank类
     public class Tank : ICar
  {
      public void Run(int run)
      {
          Console.WriteLine($"Tank Run {run}!");
      }
  }
  //未实现的实现接口BigTank类
   [Unfinished]//未完成标识
  public class BigTank : ICar
  {
      public void Run(int run)
      {
          Console.WriteLine($"BigTank Run {run}!");
      }
  }

步骤C,创建主程序这里使用控制台程序进行演示
步骤D,引用接口ICar
步骤E,使用Directory中的GetFiles方法获取指定目录( 存放dll的文件夹目录)下的所有的文件

var dataPath = Path.Combine(Environment.CurrentDirectory,"Data");//实现接口dll文件的存放目录路径
if (!Directory.Exists(dataPath))//如果Data文件夹不存在则创建
Directory.CreateDirectory(dataPath);
var files = Directory.GetFiles(dataPath);//获取目录下载所有文件

步骤F, 遍历每个文件并使用 Assembly中的LoadFile()方法来获取所有加载文件的程序集(Assembly)

 Assembly assembly = Assembly.LoadFile(file);//加载遍历到的每一个dll文件

步骤G,遍历使用Assembly中的GetTypes()方法获取到的所有类型(Type)

 var ts = assembly.GetTypes();//获取dll所有的数据类型

步骤H,根据需要判断每个类型是否包含指定的接口或其他的类型

  if(t.GetInterfaces().Contains(typeof(ICar)))//判断每一个ts遍历项是否包含ICar实现的类型

步骤I:判断是否有未完成的实现类型,存在[Unfinished]属性标识的接口实现类

   var isUnfinished=t.GetCustomAttributes(false).Any(a => a.GetType() == typeof(UnfinishedAttribute));//判断类型的属性为Unfinish

步骤J:使用反射创建实例并调用实例方法

object o= Activator.CreateInstance(currType);//根据数据类型使用反射创建实例
ICar car= o as ICar;//进行强制类型转换
car.Run(runLen);//调用Run方法

完整实现代码:

        static void Main(string[] args)
        {
            var dataPath = Path.Combine(Environment.CurrentDirectory,"Data");
            if (!Directory.Exists(dataPath))
            {
                Directory.CreateDirectory(dataPath);
            }
            var files = Directory.GetFiles(dataPath);
            var dataType = new List<Type>();
            foreach (var file in files)
            {
                Assembly assembly = Assembly.LoadFile(file);//加载dll文件
                var ts = assembly.GetTypes();//获取dll所有的数据类型
                foreach (var t in ts)
                {
                 if(t.GetInterfaces().Contains(typeof(ICar)))//判断当前数据类型的所有继承或实现的接口是否包含ICar接口
                    {
                      var isUnfinished=t.GetCustomAttributes(false).Any(a => a.GetType() == typeof(UnfinishedAttribute));//判断类型的属性为Unfinish
                        if(!isUnfinished)
                        {
                            dataType.Add(t);
                        }
                    }
                }
            }

            while (true)
            {
                Console.WriteLine("*********************************************************");
                for (int i = 0; i < dataType.Count; i++)
                {
                    Console.WriteLine($"{i + 1}. {dataType[i].Name}");
                }
                Console.WriteLine("请选择类型!");
                int typeIndex = Convert.ToInt32(Console.ReadLine());
                if (typeIndex < 1 || typeIndex > dataType.Count)
                {
                    Console.WriteLine("没有找到选择的类型,请重试");
                    continue;
                }
                var currType = dataType[typeIndex - 1];//获取选中的数据类型
                Console.WriteLine("请选择运行路程!");
                int runLen = Convert.ToInt32(Console.ReadLine());
                //强类型方式调用Run方法
                object o= Activator.CreateInstance(currType);//根据数据类型使用反射创建实例
                ICar car= o as ICar;//进行强制类型转换
                car.Run(runLen);//调用Run方法
                Console.WriteLine("*********************************************************");
            }



        }

反射扩展知识:
可以使用弱类型(object)实例调用实例方法,此种方式可能存在在调用实例方法时存在MethodInfo为null的异常的异常,因此不建议使用
实现代码:

MethodInfo mi = currType.GetMethod("Run");//获取当前数据类型中的Run方法,如果没有则此处为null
object obj = Activator.CreateInstance(currType);//根据数据类型创建object对象实例
mi.Invoke(obj, new object[] { runLen });//调用obhect对象实现run方法

完整代码:

 static void Main(string[] args)
        {
            //定义路径
            var dataPath = Path.Combine(Environment.CurrentDirectory, "Data");
            if (!Directory.Exists(dataPath))
            {
                Directory.CreateDirectory(dataPath);
            }
            //加载外部dll
            var files = Directory.GetFiles(dataPath);
            var dataType = new List<Type>();
            foreach (var file in files)
            {
                Assembly assembly = Assembly.LoadFrom(file);
                var ts = assembly.GetTypes();
                foreach (var t in ts)
                {
                    if (t.GetMethod("Run") != null)//过滤不包含Run方法的数据类型
                    {
                        var isUnfinished = t.GetCustomAttributes(false).Any(a => a.GetType() == typeof(UnfinishedAttribute));//判断类型的属性为Unfinish
                        if (!isUnfinished)
                        {
                            dataType.Add(t);
                        }
                    }
                }
            }

            while (true)
            {
                Console.WriteLine("*********************************************************");
                for (int i = 0; i < dataType.Count; i++)
                {
                    Console.WriteLine($"{i + 1}. {dataType[i].Name}");
                }
                Console.WriteLine("请选择类型!");
                int typeIndex = Convert.ToInt32(Console.ReadLine());
                if (typeIndex < 1 || typeIndex > dataType.Count)
                {
                    Console.WriteLine("没有找到选择的类型,请重试");
                    continue;
                }
                var currType = dataType[typeIndex - 1];//获取当前选中的数据类型
                Console.WriteLine("请选择运行路程!");
                int runLen = Convert.ToInt32(Console.ReadLine());
                MethodInfo mi = currType.GetMethod("Run");//获取当前数据类型中的Run方法,如果没有则此处为null
                                                          //弱类型方式进行方法调用
                object obj = Activator.CreateInstance(currType);//根据数据类型创建object对象实例
                mi.Invoke(obj, new object[] { runLen });//调用obhect对象实现run方法
                Console.WriteLine("*********************************************************");
            }



        }

Demo实例
实现效果
水平有限,欢迎大家留言交流

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

点点滴滴_每天进步一点点!!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值