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都进行了封装,有好几个版本,如动态参数,键值对等等,自己也可以参照约定,自定义实现。



 

posted on 2012-09-24 17:02  Qlin  阅读(2414)  评论(0编辑  收藏  举报