C# 反射的基本用法

1 篇文章 0 订阅

反射指程序可以访问、检测和修改它本身状态或行为的一种能力。
程序集包含模块,而模块包含类型,类型又包含成员。反射则提供了封装程序集、模块和类型的对象。
您可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型。然后,可以调用类型的方法或访问其字段和属性。

一、 场景

假设有一个类SoftwareRuns用来存放电脑软件的运行状态,最开始的时候,电脑只有三个软件,微信、腾讯QQ和Snipaste截图。

1.1 场景一

    /// <summary>
    /// 软件运行
    /// </summary>
    public class SoftwareRuns
    {
        private bool _isWeChat;
        /// <summary>
        /// 微信
        /// </summary>
        [Description("微信")]
        public bool IsWeChat
        {
            get { return _isWeChat; }
            private set { _isWeChat = value; }
        }

        private bool _isQQScLauncher;
        /// <summary>
        /// 腾讯QQ
        /// </summary>
        [Description("腾讯QQ")]
        public bool IsQQScLauncher
        {
            get { return _isQQScLauncher; }
            private set { _isQQScLauncher = value; }
        }

        private bool _isSnipaste;
        /// <summary>
        /// Snipaste截图
        /// </summary>
        [Description("Snipaste截图")]
        public bool IsSnipaste
        {
            get { return _isSnipaste; }
            private set { _isSnipaste = value; }
        }

        public SoftwareRuns(bool isWeChat,bool isQQScLauncher,bool isSnipaste)
        {
            this.IsWeChat = IsWeChat;
            this.IsQQScLauncher = isQQScLauncher;
            this.IsSnipaste = isSnipaste;
        }
    }

代码段public SoftwareRuns(bool isWeChat,bool isQQScLauncher,bool isSnipaste),在电脑只有三个软件的时候,初始化并没有多大的问题。一旦我后面又加了一堆属性后,就会发现重复的代码增多了。

        private bool _isDevenv;
        /// <summary>
        /// VisualStudio2017
        /// </summary>
        [Description("VisualStudio2017")]
        public bool IsDevenv
        {
            get { return _isDevenv; }
            private set { _isDevenv = value; }
        }

        private bool _isSsms;
        /// <summary>
        /// ManagementStudio2012
        /// </summary>
        [Description("ManagementStudio2012")]
        public bool IsSsms
        {
            get { return _isSsms; }
            private set { _isSsms = value; }
        }

        public SoftwareRuns(bool isWeChat, bool isQQScLauncher, bool isSnipaste, bool isDevenv)
        {
            this.IsWeChat = IsWeChat;
            this.IsQQScLauncher = isQQScLauncher;
            this.IsSnipaste = isSnipaste;
            this.IsDevenv = isDevenv;
        }

这仅仅只是加了一个形参,如果后面电脑安装了N多的软件后,这个类的初始化的形参需要多少个?

1.1.1 原因

类的属性不断增加。

1.1.2 目的

类初始化代码时,减少重复性代码。

1.1.3 方案

为了解决这种现象,早上在论坛里请教大佬们如何缩减代码,最后采用了大佬@Bridge_go的建议,使用字典对类进行实例化。

        /// <summary>
        /// 通过反射修改属性
        /// Dictionary<属性名,值>
        /// </summary>
        /// <param name="_dic"></param>
        public SoftwareRuns(Dictionary<string, bool> _dic)
        {
            Type type = GetType();
            foreach (var item in _dic)
            {
                PropertyInfo info = type.GetProperty(item.Key);//获取属性
                if (info != null)
                    info.SetValue(this, item.Value, null);//设置属性值
            }
        }

形式参数Dictionary<string, bool> ,string存放SoftwareRuns的属性名,bool存放SoftwareRuns的属性值。利用放射循环遍历替换SoftwareRuns的值。

SetValue:第一个参数填写将设置其属性值的对象,如果初始化了一个SoftwareRuns对象sr,那么填sr,这里不同,没有传入其他对象,那么用this关键字来代替。

这么一改,初始化对象可能有些啰嗦了,因为都是bool类型的属性,我只在字典添加了为True的值。

普通初始化
普通初始化
对象初始化
对象的初始化

 

 

 

 

 

 

 

1.2 场景二

打开任务管理器类TaskManager,想要看看有哪些程序正在运行。

        /// <summary>
        /// 输出
        /// </summary>
        /// <param name="software"></param>
        public void Print(SoftwareRuns software)
        {
            StringBuilder sb = new StringBuilder();
            if (software.IsWeChat)
                sb.AppendLine("微信运行中!");
            if (software.IsQQScLauncher)
                sb.AppendLine("腾讯QQ运行中!");
            if (software.IsSnipaste)
                sb.AppendLine("截图软件运行中!");
            Console.WriteLine(sb.ToString());
        }

 随着软件增多,Print方法将会 变得十分臃肿。

1.2.1 原因

if...else判断过多。

1.2.2 目的

缩减if..else分支,减少重复性代码。

1.2.3 方案

通过PropertyInfo来获取属性的信息。

        /// <summary>
        /// 输出
        /// </summary>
        /// <param name="software"></param>
        public void Print(SoftwareRuns software)
        {
            StringBuilder sb = new StringBuilder();
            Type type = software.GetType();
            foreach (PropertyInfo info in type.GetProperties())
            {
                bool IsRun = Convert.ToBoolean(info.GetValue(software, null));//获取属性值
                if (IsRun)
                {
                    //获取属性注释
                    string name = info.GetCustomAttributes(typeof(DescriptionAttribute), true).Cast<DescriptionAttribute>().SingleOrDefault().Description;
                    sb.AppendLine(name + "运行中!");
                }
            }
            Console.WriteLine(sb.ToString());
        }
普通Print
普通Print
动态Print
动态Print

 

 

 

 

 

 

1.3 场景三

某些情况下,if...else判断中,执行方法仅仅只有某个入参值不一样。

        /// <summary>
        /// 微信安装路径
        /// </summary>
        private Uri WeChatURI { get { return new Uri(@"D:\WeChat"); } }

        /// <summary>
        /// 腾讯QQ安装路径
        /// </summary>
        private Uri QQScLauncherURI { get { return new Uri(@"D:\TencentQQ"); } }

        /// <summary>
        /// Snipaste截图软件安装路径
        /// </summary>
        private Uri SnipasteURI { get { return new Uri(@"D:\Snipaste"); } }

        /// <summary>
        /// 关闭应用程序
        /// </summary>
        /// <param name="software"></param>
        public void Close(SoftwareRuns software)
        {
            if (software.IsWeChat)
                CloseApplication("微信", WeChatURI);
            if (software.IsQQScLauncher)
                CloseApplication("腾讯QQ",QQScLauncherURI);
            if (software.IsSnipaste)
                CloseApplication("Snipaste", SnipasteURI);
        }


        private void CloseApplication(string name,Uri uri)
        {
            Console.WriteLine("应用程序:" + name + ",已成功关闭!\n路径:" + uri.LocalPath);
        }

 

1.3.1 原因

if...else判断过多。

1.3.2 目的

缩减if..else分支,减少重复性代码。

1.3.3 方案

通过PropertyInfo和Activator来缩减代码。

        /// <summary>
        /// 关闭应用程序
        /// </summary>
        /// <param name="software"></param>
        public void Close(SoftwareRuns software)
        {
            Type type = software.GetType();
            //命名和URI的规范【格式:info.Name.Substring(2) + "URI"】
            foreach (PropertyInfo info in type.GetProperties())
            {
                if (!Convert.ToBoolean(info.GetValue(software, null))) //应用程序没启动直接跳过
                    continue;
                var function = Activator.CreateInstance<TaskManager>();
                //重载的情况下需要指明参数类型
                var method = function.GetType().GetMethod("CloseApplication", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, Type.DefaultBinder, new Type[] { typeof(string), typeof(Uri) }, new ParameterModifier[] { new ParameterModifier(2) });
                object[] methodPara = new object[2];
                methodPara[0] = info.GetCustomAttributes(typeof(DescriptionAttribute), true).Cast<DescriptionAttribute>().SingleOrDefault().Description;
                //根据属性名动态获取URI路径
                string url = info.Name.Substring(2) + "URI";
                PropertyInfo p = GetType().GetProperty(url, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);//避免属性为私有的
                if (p == null)
                    continue;
                Uri uri = p.GetValue(this, null) as Uri;
                methodPara[1] = uri;
                object result = method.Invoke(function, methodPara);
            }
        }
普通方式
普通方式
动态形式
动态形式

 

以上内容只为方便理解

二、资源链接

百度网盘:https://pan.baidu.com/s/1YWUA--Bb7vdUOo7-mnaIgQ 提取码:wwqp

CSND:https://download.csdn.net/download/Dear200892/12598300

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值