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