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