Click here to Skip to main content
15,885,278 members
Articles / Programming Languages / C#

.NET Scheduled Timer

Rate me:
Please Sign up or sign in to vote.
4.89/5 (139 votes)
16 Sep 2005CPOL15 min read 1.1M   38.4K   361  
A timer that easily supports absolute schedules like run at 4:00 AM every day or at 5:00 PM on Fridays..
using System;
using System.Collections;
using System.Reflection;
using System.Text.RegularExpressions;

namespace Schedule
{
	/// <summary>
	/// IParameterSetter represents a serialized parameter list.  This is used to provide a partial specialized
	/// method call.  This is useful for remote invocation of method calls.  For example if you have a method with
	/// 3 parameters.  The first 2 might represent static data such as a report and a storage location.  The third
	/// might be the time that the report is invoked, which is only known when the method is invoked.  Using this,
	/// you just pass the method and the first 2 parameters to a timer object, which supplies the 3rd parameter.
	/// Without these objects, you would have to generate a custom object type for each method you wished to 
	/// execute in this manner and store the static parameters as instance variables.  
	/// </summary>
	public interface IParameterSetter
	{
		/// <summary>
		/// This resets the setter to the beginning.  It is used for setters that rely on positional state
		/// information.  It is called prior to setting any method values.
		/// </summary>
		void reset();
		/// <summary>
		/// This method is used to both query support for setting a parameter and actually set the value.
		/// True is returned if the parameter passed in is updated.
		/// </summary>
		/// <param name="pi">The reflection information about this parameter.</param>
		/// <param name="ParameterLoc">The location of the prameter in the parameter list.</param>
		/// <param name="parameter">The parameter object</param>
		/// <returns>true if the parameter is matched and false otherwise</returns>
		bool GetParameterValue(ParameterInfo pi, int ParameterLoc, ref object parameter);
	}

	/// <summary>
	/// This setter object takes a simple object array full of parameter data.  It applys the objects in order
	/// to the method parameter list.
	/// </summary>
	public class OrderParameterSetter : IParameterSetter
	{
		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;
		}

		object[] _ParamList;
		int _counter;
	}

	/// <summary>
	/// This setter object stores the parameter data in a Hashtable and uses the hashtable keys to match 
	/// the parameter names of the method to the parameter data.  This allows methods to be called like 
	/// stored procedures, with the parameters being passed in independent of order.
	/// </summary>
	public class NamedParameterSetter : IParameterSetter
	{
		public NamedParameterSetter(Hashtable Params)
		{
			_Params = Params;
		}
		public void reset()
		{
		}
		public bool GetParameterValue(ParameterInfo pi, int ParameterLoc, ref object parameter)
		{
			string ParamName = pi.Name;
			if (!_Params.ContainsKey(ParamName))
				return false;
			parameter = _Params[ParamName];
			return true;
		}
		Hashtable _Params;
	}


	/// <summary>
	/// ParameterSetterList maintains a collection of IParameterSetter objects and applies them in order to each
	/// parameter of the method.  Each time a match occurs the next parameter is tried starting with the first 
	/// setter object until it is matched.
	/// </summary>
	public class ParameterSetterList
	{
		public void Add(IParameterSetter setter)
		{
			_List.Add(setter);
		}

		public IParameterSetter[] ToArray()
		{
			return (IParameterSetter[])_List.ToArray(typeof(IParameterSetter));
		}

		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];
			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];
			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;
		}

		ArrayList _List = new ArrayList();
	}

	/// <summary>
	/// IMethodCall represents a partially specified parameter data list and a method.  This allows methods to be 
	/// dynamically late invoked for things like timers and other event driven frameworks.
	/// </summary>
	public interface IMethodCall
	{
		ParameterSetterList ParamList { get; }
		object Execute();
		object Execute(IParameterSetter Params);
		IAsyncResult BeginExecute(AsyncCallback callback, object obj);
		IAsyncResult  BeginExecute(IParameterSetter Params, AsyncCallback callback, object obj);
	}

	delegate object Exec();
	delegate object Exec2(IParameterSetter Params);

	/// <summary>
	/// Method call captures the data required to do a defered method call.
	/// </summary>
	public class DelegateMethodCall : MethodCallBase, IMethodCall
	{
		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);
		}

		Delegate _f;

		public Delegate f
		{
			get { return _f; }
			set { _f = value; }
		}

		public MethodInfo Method
		{
			get { return _f.Method; }
		}

		public object Execute()
		{
			return f.DynamicInvoke(GetParameterList(Method));
		}

		public object Execute(IParameterSetter Params)
		{
			return f.DynamicInvoke(GetParameterList(Method, Params));
		}

		Exec _exec;
		public IAsyncResult BeginExecute(AsyncCallback callback, object obj)
		{
			_exec = new Exec(Execute);
			return _exec.BeginInvoke(callback, obj);
		}

		public IAsyncResult BeginExecute(IParameterSetter Params, AsyncCallback callback, object obj)
		{
			Exec2 exec = new Exec2(Execute);
			return exec.BeginInvoke(Params, callback, obj);
		}
	}

	public class DynamicMethodCall : MethodCallBase, IMethodCall
	{
		public DynamicMethodCall(MethodInfo method)
		{
			_obj = null;
			_method = method;
		}

		public DynamicMethodCall(object obj, MethodInfo method)
		{
			_obj = obj;
			_method = method;
		}

		public DynamicMethodCall(object obj, MethodInfo method, IParameterSetter setter)
		{
			_obj = obj;
			_method = method;
			ParamList.Add(setter);
		}

		object _obj;
		MethodInfo _method;

		public MethodInfo Method
		{
			get { return _method; }
			set { _method = value; }
		}

		public object Execute()
		{
			return _method.Invoke(_obj, GetParameterList(Method));
		}

		public object Execute(IParameterSetter Params)
		{
			return _method.Invoke(_obj, GetParameterList(Method, Params));
		}

		Exec _exec;
		public IAsyncResult BeginExecute(AsyncCallback callback, object obj)
		{
			_exec = new Exec(Execute);
			return _exec.BeginInvoke(callback, null);
		}

		public IAsyncResult BeginExecute(IParameterSetter Params, AsyncCallback callback, object obj)
		{
			Exec2 exec = new Exec2(Execute);
			return exec.BeginInvoke(Params, callback, null);
		}
	}

	/// <summary>
	/// This is a base class that handles the Parameter list management for the 2 dynamic method call methods.
	/// </summary>
	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;
		}
	}

}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) Standard Beagle Studios
United States United States
I co-founded Standard Beagle Studio, a software development consulting service in Austin Texas with my wife Cindy Brummer. We focus mostly on web projects, but have built some react native mobile apps, and even a windows screen saver or two.

I started my career back when ASP pages were state of the art, and IE3 was considered a web browser. I've worked with Microsoft technologies for most of that time, and have recently branched out into node, wordpress, and react native applications.

I'm a web developer, math and physics enthusiast, father of 2, and all around great guy. I live in Austin TX and love using technology to change people's lives for the better. When I manage scrape together some spare time, I build generative art at curvature of the mind.

Comments and Discussions