using System; using System.Collections.Generic; using System.Reflection; using System.Text; using Csla.Properties; namespace Csla { internal static class MethodCaller { const BindingFlags allLevelFlags = BindingFlags.FlattenHierarchy | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; const BindingFlags oneLevelFlags = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; /// /// Gets a reference to the DataPortal_Create method for /// the specified business object type. /// /// Type of the business object. /// Criteria parameter value. /// /// If the criteria parameter value is an integer, that is a special /// flag indicating that the parameter should be considered missing /// (not Nothing/null - just not there). /// public static MethodInfo GetCreateMethod(Type objectType, object criteria) { MethodInfo method = null; if (criteria is int) { // an "Integer" criteria is a special flag indicating // that criteria is empty and should not be used method = MethodCaller.GetMethod(objectType, "DataPortal_Create"); } else method = MethodCaller.GetMethod(objectType, "DataPortal_Create", criteria); return method; } /// /// Gets a reference to the DataPortal_Fetch method for /// the specified business object type. /// /// Type of the business object. /// Criteria parameter value. /// /// If the criteria parameter value is an integer, that is a special /// flag indicating that the parameter should be considered missing /// (not Nothing/null - just not there). /// public static MethodInfo GetFetchMethod(Type objectType, object criteria) { MethodInfo method = null; if (criteria is int) { // an "Integer" criteria is a special flag indicating // that criteria is empty and should not be used method = MethodCaller.GetMethod(objectType, "DataPortal_Fetch"); } else method = MethodCaller.GetMethod(objectType, "DataPortal_Fetch", criteria); return method; } /// /// Uses reflection to dynamically invoke a method /// if that method is implemented on the target object. /// public static object CallMethodIfImplemented( object obj, string method, params object[] parameters) { MethodInfo info = GetMethod(obj.GetType(), method, parameters); if (info != null) return CallMethod(obj, info, parameters); else return null; } /// /// Uses reflection to dynamically invoke a method, /// throwing an exception if it is not /// implemented on the target object. /// public static object CallMethod( object obj, string method, params object[] parameters) { MethodInfo info = GetMethod(obj.GetType(), method, parameters); if (info == null) throw new NotImplementedException( method + " " + Resources.MethodNotImplemented); return CallMethod(obj, info, parameters); } /// /// Uses reflection to dynamically invoke a method, /// throwing an exception if it is not /// implemented on the target object. /// public static object CallMethod( object obj, MethodInfo info, params object[] parameters) { // call a private method on the object object result; try { result = info.Invoke(obj, parameters); } catch (Exception e) { throw new Csla.Server.CallMethodException( info.Name + " " + Resources.MethodCallFailed, e.InnerException); } return result; } /// /// Uses reflection to locate a matching method /// on the target object. /// public static MethodInfo GetMethod( Type objectType, string method, params object[] parameters) { MethodInfo result = null; // try to find a strongly typed match // put all param types into a list of Type List types = new List(); foreach (object item in parameters) { if (item == null) types.Add(typeof(object)); else types.Add(item.GetType()); } // first see if there's a matching method // where all params match types result = FindMethod(objectType, method, types.ToArray()); if (result == null) { // no match found - so look for any method // with the right number of parameters result = FindMethod(objectType, method, parameters.Length); } // no strongly typed match found, get default if (result == null) { try { result = objectType.GetMethod(method, allLevelFlags); } catch (AmbiguousMatchException) { MethodInfo[] methods = objectType.GetMethods(); foreach (MethodInfo m in methods) if (m.Name == method && m.GetParameters().Length == parameters.Length) { result = m; break; } if (result == null) throw; } } return result; } /// /// Returns a business object type based on /// the supplied criteria object. /// public static Type GetObjectType(object criteria) { if (criteria.GetType().IsSubclassOf(typeof(CriteriaBase))) { // get the type of the actual business object // from CriteriaBase return ((CriteriaBase)criteria).ObjectType; } else { // get the type of the actual business object // based on the nested class scheme in the book return criteria.GetType().DeclaringType; } } /// /// Returns information about the specified /// method, even if the parameter types are /// generic and are located in an abstract /// generic base class. /// public static MethodInfo FindMethod(Type objType, string method, Type[] types) { MethodInfo info = null; do { //find for a strongly typed match info = objType.GetMethod(method, oneLevelFlags, null, types, null); if (info != null) break; //match found objType = objType.BaseType; } while (objType != null); return info; } /// /// Returns information about the specified /// method, finding the method based purely /// on the method name and number of parameters. /// public static MethodInfo FindMethod(Type objType, string method, int parameterCount) { // walk up the inheritance hierarchy looking // for a method with the right number of // parameters MethodInfo result = null; Type currentType = objType; do { MethodInfo info = currentType.GetMethod(method, oneLevelFlags); if (info != null) { if (info.GetParameters().Length == parameterCount) { // got a match so use it result = info; break; } } currentType = currentType.BaseType; } while (currentType != null); return result; } } }