/*************************************************************************** * Copyright Andy Brummer 2004-2005 * * This code is provided "as is", with absolutely no warranty expressed * or implied. Any use is at your own risk. * * This code may be used in compiled form in any way you desire. This * file may be redistributed unmodified by any means provided it is * not sold for profit without the authors written consent, and * providing that this notice and the authors name is included. If * the source code in this file is used in any commercial application * then a simple email would be nice. * **************************************************************************/ using System; using System.Collections; using System.Reflection; using System.Text.RegularExpressions; namespace UtilidadesCSharp.Schedule { /// /// 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. /// public interface IParameterSetter { /// /// 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. /// void reset(); /// /// 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. /// /// The reflection information about this parameter. /// The location of the prameter in the parameter list. /// The parameter object /// true if the parameter is matched and false otherwise bool GetParameterValue(ParameterInfo pi, int ParameterLoc, ref object parameter); } /// /// This setter object takes a simple object array full of parameter data. It applys the objects in order /// to the method parameter list. /// 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; } /// /// 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. /// 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; } /// /// 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. /// 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]; //TODO: Update to iterate backwards for(int i=0; i /// 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. /// 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); } delegate object Exec(); delegate object Exec2(IParameterSetter Params); /// /// Method call captures the data required to do a defered method call. /// 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)); } public void EventHandler(object obj, EventArgs e) { Execute(); } 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)); } public void EventHandler(object obj, EventArgs e) { Execute(); } 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); } } /// /// This is a base class that handles the Parameter list management for the 2 dynamic method call methods. /// 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; } } }