zoukankan      html  css  js  c++  java
  • [Scheduled Timer]第五回:任务方法(MethodCall)

    1.引言

    Scheduled Timer的由Timer定时器触发执行任务,Timer每隔一段时间(短时间)触发Elapsed事件,大多数做法是给定时器Timer的Elapsed事件赋值,Scheduled Timer的做法差不多,但又有不同。Scheduled Timer做法是把定时器的Elapsed私有化了,给了它一个固定私有的方法Timer_Elapsed,在Timer_Elapsed里有多个Job,每个Job才是对应我们的任务方法。里我们并不是在调用时给Elapsed赋值,Elapsed事件只是一个入口,在Elapsed事件里进行执行我们的任务方法,这个任务方法可以是一个,也可以是集合,这个方法里面的参数也是动态的,可以是外部传入,也可以说是线程里执行时传入。这节介绍任务方法。

    2.任务方法

    Job下的MethodCall是我们的任务方法,大家肯定想到了委托,对的,Scheduled Timer也是使用委托,因为它可以赋值一个方法签名。有了方法,另一个就是方法参数,参数值,可以初始化时传入,可以Timer执行时动态创建参数或者修改,这些委托都可以办到。先来看看委托Delegate的DynamicInvoke声明,Scheduled Timer就用到它。

        [Serializable]
        [ClassInterface(ClassInterfaceType.AutoDual)]
        [ComVisible(true)]
        public abstract class Delegate : ICloneable, ISerializable
        {
            //
            // 摘要:
            //     动态调用(后期绑定)由当前委托所表示的方法。
            //
            // 参数:
            //   args:
            //     作为参数传递给当前委托所表示的方法的对象数组。- 或 -如果当前委托所表示的方法不需要参数,则为 null。
            //
            // 返回结果:
            //     委托所表示的方法返回的对象。
            //
            // 异常:
            //   System.MemberAccessException:
            //     调用方不能访问委托所表示的方法(例如,当该方法为私有时)。- 或 -args 中列出的参数的数目、顺序或类型无效。
            //
            //   System.Reflection.TargetException:
            //     委托所表示的方法是实例方法,目标对象为 null。- 或 -对对象或类调用委托所表示的方法,但该对象或类不支持这种方法。
            //
            //   System.Reflection.TargetInvocationException:
            //     封装的方法之一引发异常。
            [SecuritySafeCritical]
            public object DynamicInvoke(params object[] args);
        }

    参数args不只是我们初始化时传入,而且还可以在运行中动态添加、修改参数。于是我们要定义一个自己的参数类,方便操作。

        /// <summary>
        /// 参数设置器
        /// </summary>
        public interface IParameterSetter
        {
            /// <summary>
            /// 设置获取第N个参数
            /// </summary>
            void reset();
    
            /// <summary>
            /// 获取参数值
            /// </summary>
            /// <param name="pi"></param>
            /// <param name="ParameterLoc">第几个参数</param>
            /// <param name="parameter">参数值</param>
            /// <returns>是否成功获取</returns>
            bool GetParameterValue(ParameterInfo pi, int ParameterLoc, ref object parameter);
        }
    IParameterSetter接口做两件事:
    • reset() 设置获取参数的起始值,一般设为0
    • GetParameterValue 获取第N个参数的值

    接下来简单实现一个IParameterSetter如下:

        /// <summary>
        /// 动态参数类
        /// </summary>
        public class OrderParameterSetter : IParameterSetter
        {
            object[] _paramList;
            int _counter;
    
            public OrderParameterSetter(params object[] _params)
            {
                _paramList = _params;
            }
    
            public void reset()
            {
                _counter = 0;
            }
    
            public bool GetParameterValue(ParameterInfo pi, int parameterLoc, ref object parameter)
            {
                if (_counter >= _paramList.Length)
                    return false;
    
                parameter = _paramList[_counter++];
                return true;
            }
        }

    在OrderParameterSetter中看到构造函数我们知道,这个参数类可以动态构造多个值,譬如一个方法有10个参数,你可以使用OrderParameterSetter来初始化前面5个,后面运行时的时候再初始化后面5个。由此就引出一个问题,我们的IParameterSetter 不是一个,后面再动态创建时会有多个,于是,我们要在任务方法里创建一个IParameterSetter的集合,Scheduled Timer为了方便管理,自定义了一个类来管理。

        /// <summary>
        ///参数类收集器
        /// </summary>
        public class ParameterSetterList
        {
            List<IParameterSetter> _List = new List<IParameterSetter>();
    
            public void Add(IParameterSetter setter)
            {
                _List.Add(setter);
            }
    
            public IParameterSetter[] ToArray()
            {
                return _List.ToArray();
            }
    
            public void reset()
            {
                foreach (IParameterSetter Setter in _List)
                    Setter.reset();
            }
    
            public object[] GetParameters(MethodInfo Method)
            {
                ParameterInfo[] Params = Method.GetParameters();
                object[] Values = new object[Params.Length];
                //TODO: Update to iterate backwards
                for (int i = 0; i < Params.Length; ++i)
                    SetValue(Params[i], i, ref Values[i]);
    
                return Values;
            }
    
            public object[] GetParameters(MethodInfo Method, IParameterSetter LastSetter)
            {
                ParameterInfo[] Params = Method.GetParameters();
                object[] Values = new object[Params.Length];
                //TODO: Update to iterate backwards
                for (int i = 0; i < Params.Length; ++i)
                {
                    if (!SetValue(Params[i], i, ref Values[i]))
                        LastSetter.GetParameterValue(Params[i], i, ref Values[i]);
                }
                return Values;
            }
    
            bool SetValue(ParameterInfo Info, int i, ref object Value)
            {
                foreach (IParameterSetter Setter in _List)
                {
                    if (Setter.GetParameterValue(Info, i, ref Value))
                        return true;
                }
                return false;
            }        
        }
    ParameterSetterList类比较简单,就是管理多个IParameterSetter。
    参数建好接下来就是我们的方法了,Scheduled Timer里面是用继承来实现的,而非组合,这样可以简化方法类,先看基类。
        public class MethodCallBase
        {
            ParameterSetterList _paramList = new ParameterSetterList();
    
            public ParameterSetterList ParamList
            {
                get { return _paramList; }
            }
    
            protected object[] GetParameterList(MethodInfo method)
            {
                ParamList.reset();
                object[] Params = ParamList.GetParameters(method);
                return Params;
            }
    
            protected object[] GetParameterList(MethodInfo method, IParameterSetter _params)
            {
                ParamList.reset();
                object[] objParams = ParamList.GetParameters(method, _params);
                return objParams;
            }
        }

    接下来就继承MethodCallBaseScheduled Timer 里有多个版本实现,这里介绍DelegateMethodCall

        /// <summary>
        ///方法执行的接口
        /// </summary>
        public interface IMethodCall
        {
            ParameterSetterList ParamList { get; }
            object Execute();
            object Execute(IParameterSetter Params);
            void EventHandler(object obj, EventArgs e);
            IAsyncResult BeginExecute(AsyncCallback callback, object obj);
            IAsyncResult BeginExecute(IParameterSetter Params, AsyncCallback callback, object obj);
        }
        public class DelegateMethodCall : MethodCallBase, IMethodCall
        {
            Delegate _f;
    
            public DelegateMethodCall(Delegate f)
            {
                _f = f;
            }
    
            public DelegateMethodCall(Delegate f, params object[] Params)
            {
                if (f.Method.GetParameters().Length < Params.Length)
                    throw new ArgumentException("Too many parameters specified for delegate", "f");
    
                _f = f;
                ParamList.Add(new OrderParameterSetter(Params));
            }
    
            public DelegateMethodCall(Delegate f, IParameterSetter Params)
            {
                _f = f;
                ParamList.Add(Params);
            }
    
            public object Execute()
            {
                return _f.DynamicInvoke(GetParameterList(_f.Method));
            }
    
            public object Execute(IParameterSetter Params)
            {
                return _f.DynamicInvoke(GetParameterList(_f.Method, Params));
            }
        }

    IMethodCall接口来约束,提供了 异步调用,同步调用多个版本,DelegateMethodCall 是其中的一个实现。

    调用也很简单

     Action<string> delM=o => { Console.WriteLine(o); };
     IMethodCall method = new DelegateMethodCall(delM, "hello method");
    method.Execute();

    3.总结

    动态调用方法,都是利用委托,为了方便使用,参数类,方法Scheduled Timer都进行了封装,有好几个版本,如动态参数,键值对等等,自己也可以参照约定,自定义实现。



     

  • 相关阅读:
    《大话设计模式》的一些总结
    一个仿jdkd的动态代理
    一道笔试题(构造数组)
    c# 汉字转拼音
    IDEA常用插件盘点(香~~)
    服务器概念、应用服务器盘点大科普
    创建一个简单的Struts 2程序
    JAVA(Object类、Date类、Dateformat类、Calendar类)
    DQL查询语句和约束
    MySQL操作语句
  • 原文地址:https://www.cnblogs.com/qqlin/p/2694087.html
Copyright © 2011-2022 走看看