C# 自定义特性Attribute与反射调用


前言

👨‍💻👨‍🌾📝记录学习成果,以便温故而知新

  一个项目有对个打印任务,每个打印任务调用不同的Excel模板进行打印。利用自定义特性PrintTaskAttribute来标识打印任务函数,再利用反射的方法把打印任务名与打印方法的映射关系存到字典里。以下是把项目中的思路抽出来整了个演示项目。

项目结构如下:
项目结构

1.AttributeUtil.cs

文件中含AttributeUtil(特性工具类)、PrintTaskAttribute(打印任务特性)与ObjectMethodInfo(特性内容与映射方法类)。AttributeUtil工具类有MapPrintTaskToMethod与InvokePrintTask两个方法,MapPrintTaskToMethod方法映射程序集中所有含打印任务特性的方法,InvokePrintTask调用映射的打印任务方法。

namespace Print
{
    /// <summary>
    /// 特性工具类
    /// <para>author: Antonio</para>
    /// </summary>
    class AttributeUtil
    {
        /// <summary>
        /// 打印任务映射处理方法
        /// <para>author: Antonio</para>
        /// </summary>
        /// <param name="objectMethodDictionary">打印任务与调用方法映射字典</param>
        /// <param name="assemblyName">程序集</param>
        public void MapPrintTaskToMethod(out Dictionary<string, ObjectMethodInfo> objectMethodDictionary, string assemblyName)
        {
            objectMethodDictionary = new Dictionary<string, ObjectMethodInfo>();

            Assembly assembly = Assembly.Load(assemblyName);
            Type[] types = assembly.GetTypes();

            foreach (Type t in types)
            {
                object _Object = null;
                //Debug.WriteLine(t.FullName, "类名");

                MethodInfo[] methodInfos = t.GetMethods();

                foreach (MethodInfo methodInfo in methodInfos)
                {
                    //Debug.WriteLine(methodInfo.Name, "方法名");
                    IEnumerable<Attribute> attributes = methodInfo.GetCustomAttributes();

                    foreach (Attribute attr in attributes)
                    {
                        //Debug.WriteLine(attr.ToString(), "特性");
                        if (attr is PrintTaskAttribute)
                        {
                            PrintTaskAttribute printTaskAttribute = (PrintTaskAttribute)attr;
                            string printTaskName = printTaskAttribute.printTaskName;

                            //Debug.WriteLine(printTaskName, "PrintTaskName");
                            if (!objectMethodDictionary.ContainsKey(printTaskName))
                            {
                                ObjectMethodInfo objectMethod = new ObjectMethodInfo();
                                if (_Object == null)
                                {
                                    _Object = Activator.CreateInstance(t);
                                }
                                objectMethod._Object = _Object;//类
                                objectMethod._MethodInfo = methodInfo;//方法

                                objectMethodDictionary[printTaskName] = objectMethod;
                            }
                            else
                            {
                                Debug.Fail(t.FullName + "." + methodInfo.Name + "[" + printTaskAttribute.TypeId + "(PrintTaskName)]:" + printTaskName + "已存在");
                            }
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 调用打印任务
        /// <para>author: Antonio</para>
        /// </summary>
        /// <param name="objectMethodDictionary">打印任务与调用方法映射字典</param>
        /// <param name="printTaskName">打印任务</param>
        /// <param name="dic">参数</param>
        /// <returns></returns>
        public bool InvokePrintTask(Dictionary<string, ObjectMethodInfo> objectMethodDictionary, string printTaskName, Dictionary<string, Object> dic)
        {
            bool b = false;
            if (objectMethodDictionary.ContainsKey(printTaskName))
            {
                object o = objectMethodDictionary[printTaskName]._MethodInfo.Invoke(objectMethodDictionary[printTaskName]._Object, new object[] { dic });
                b = (bool)o;
            }
            return b;
        }
    }

    /// <summary>
    /// 打印任务特性
    /// <para>author: Antonio</para>
    /// </summary>
    [AttributeUsage(AttributeTargets.Method)]
    public class PrintTaskAttribute : Attribute
    {
        public string printTaskName { get; set; }
        public PrintTaskAttribute(string printTaskName)
        {
            this.printTaskName = printTaskName;
        }
    }

    /// <summary>
    /// 特性内容与映射方法类
    /// <para>author: Antonio</para>
    /// </summary>
    public class ObjectMethodInfo
    {
        /// <summary>
        /// 类
        /// </summary>
        public object _Object { get; set; }
        /// <summary>
        /// 类方法
        /// </summary>
        public MethodInfo _MethodInfo { get; set; }
    }
}

核心代码:

object o = objectMethodDictionary[printTaskName]._MethodInfo.Invoke(objectMethodDictionary[printTaskName]._Object, new object[] { dic });

objectMethodDictionary[printTaskName]._MethodInfo是调用的方法。
参数objectMethodDictionary[printTaskName]._Object是方法所属对象。
new object[] { dic }是传参。

2.两个打印任务类

(1)PrintTaskA.cs

模拟打印任务A下有个模板

namespace Print
{
    /// <summary>
    /// 打印任务A
    /// <para>author: Antonio</para>
    /// </summary>
    class PrintTaskA
    {
        /// <summary>
        /// 任务A-模板1
        /// <para>author: Antonio</para>
        /// </summary>
        /// <param name="dic">参数</param>
        /// <returns></returns>
        [PrintTask("任务A-模板1")]
        public bool Task_A_1(Dictionary<string, Object> dic)
        {
            Console.WriteLine("===任务A-模板1===");
            Console.WriteLine("姓名:" + dic["name"]);
            Console.WriteLine("年龄" + dic["age"]);
            return true;
        }

        /// <summary>
        /// 任务A-模板2
        /// <para>author: Antonio</para>
        /// </summary>
        /// <param name="dic">参数</param>
        /// <returns></returns>
        [PrintTask("任务A-模板2")]
        public bool Task_A_2(Dictionary<string, Object> dic)
        {
            Console.WriteLine("===任务A-模板2===");
            Console.Write("姓名:" + dic["name"]);
            Console.Write(" ");
            Console.WriteLine("年龄" + dic["age"]);
            return true;
        }
    }
}

(2)PrintTaskB.cs

模拟打印任务B下有3个模板

namespace Print
{
    /// <summary>
    /// 打印任务B
    /// <para>author: Antonio</para>
    /// </summary>
    class PrintTaskB
    {
        /// <summary>
        /// 任务B-模板1
        /// <para>author: Antonio</para>
        /// </summary>
        /// <param name="dic">参数</param>
        /// <returns></returns>
        [PrintTask("任务B-模板1")]
        public bool Task_B_1(Dictionary<string, Object> dic)
        {
            Console.WriteLine("===任务B-模板1===");
            Console.WriteLine(dic["Tom"] + "和" +dic["Jerry"] + "一起工作");
            return true;
        }

        /// <summary>
        /// 任务B-模板2
        /// <para>author: Antonio</para>
        /// </summary>
        /// <param name="dic">参数</param>
        /// <returns></returns>
        [PrintTask("任务B-模板2")]
        public bool Task_B_2(Dictionary<string, Object> dic)
        {
            Console.WriteLine("===任务B-模板1===");
            Console.WriteLine(dic["Tom"] + "帮助" + dic["Jerry"] );
            return true;
        }

        /// <summary>
        /// 任务B-模板3
        /// <para>author: Antonio</para>
        /// </summary>
        /// <param name="dic">参数</param>
        /// <returns></returns>
        [PrintTask("任务B-模板3")]
        public bool Task_B_3(Dictionary<string, Object> dic)
        {
            Console.WriteLine("===任务B-模板1===");
            Console.WriteLine(dic["Jerry"] + "帮助" + dic["Tom"]);
            return true;
        }
    }
}

3.Program.cs

演示效果代码如下:

namespace Print
{
    class Program
    {
        static void Main(string[] args)
        {
            Dictionary<string, ObjectMethodInfo> objectMethodDictionary = new Dictionary<string, ObjectMethodInfo>();
            AttributeUtil util = new AttributeUtil();

            //程序集Print中打印任务映射处理方法
            util.MapPrintTaskToMethod(out objectMethodDictionary, "Print");

            Dictionary<string, Object> dic1 = new Dictionary<string, object>();
            dic1["name"] = "Tom";
            dic1["age"] = 18;

            util.InvokePrintTask(objectMethodDictionary, "任务A-模板1", dic1);//调用任务A-模板1
            util.InvokePrintTask(objectMethodDictionary, "任务A-模板2", dic1);//调用任务A-模板3

            Dictionary<string, Object> dic2 = new Dictionary<string, object>();
            dic2["Tom"] = "Tom";
            dic2["Jerry"] = "Jerry";
            util.InvokePrintTask(objectMethodDictionary, "任务B-模板1", dic2);//调用任务B-模板1
            util.InvokePrintTask(objectMethodDictionary, "任务B-模板2", dic2);//调用任务B-模板2
            util.InvokePrintTask(objectMethodDictionary, "任务B-模板3", dic2);//调用任务B-模板3

            Console.Read();
        }
    }
}

运行效果
在实际项目中调用打印任务,打印任务名一般是以动态参数形式传入,dic参数应与打印任务匹配,这样的话如果有新的打印任务,只需新增打印任务功能方法,其它代码可以少改,甚至不需改动。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值