使用“反射”设置嵌套属性值

时间:2009-11-23 16:51:35

标签: c# .net reflection

我一直在搜索,但找不到我问题的确切答案。以下面的代码为例:

public class Company
{
    private string m_strName;
    private Customer m_objCustomer;

    public Company()
    {
        m_strName = "";
        m_objCustomer = new Customer();
    }

    public string Name
    {
        get { return m_strName; }
        set { m_strName = value; }
    }

    public Customer CustomerInformaion
    {
        get { return m_objCustomer; }
        set { m_objCustomer = value; }
    }
}

public class Customer
{
    private string m_strName;
    private Details m_objDetails;


    public Customer()
    {
        m_strName = "";
        m_objDetails = new Details();
    }

    public string Name
    {
        get { return m_strName; }
        set { m_strName = value; }
    }

    public Details CustomerDetails
    {
        get { return m_objDetails; }
        set { m_objDetails = value; }
    }
}

public class Details
{
    private string m_strPhoneNumber;
    private string m_strEmailAddress;

    public Details()
    {
        m_strPhoneNumber = "";
        m_strEmailAddress = "";
    }

    public string PhoneNumber
    {
        get { return m_strPhoneNumber; }
        set { m_strPhoneNumber = value; }
    }

    public string EmailAddress
    {
        get { return m_strEmailAddress; }
        set { m_strEmailAddress = value; }
    }
}

现在,我已经设置了一个包含许多文本字段的表单,用户可以在其中输入有关公司客户的信息。其中一个字段是电子邮件地址文本字段,其Tag属性设置为EmailAddress。我希望能够查看TextBox的Tag并遍历整个Company对象,以查找具有匹配Name的属性,并将其值设置为TextBox的Text属性。我可以找到该物业,但设定其价值已证明非常困难。这就是我到目前为止所做的:

foreach (PropertyInfo info in m_objCompany.GetType().GetProperties())
{
    if (info.PropertyType != typeof(System.String))
    {
        foreach (PropertyInfo info2 in info.PropertyType.GetProperties())
        {
            if (objTextBox.Tag.Equals(info2.Name))
            {
                if (info2.CanWrite)
                {
                    Object objValue = Convert.ChangeType(objTextBox.Text, info.PropertyType);
                    info2.SetValue(m_objCompany, objValue, null);
                }
            }

        }
    }
}

我的问题是,当我运行代码时,我收到ChangeType和/或SetValue的错误。问题是Reflection正在停止在info2并尝试将值设置为Details of Details - 因为它是Property EmailAddress的父级。

任何帮助确定如何将SetValue指向适当的属性都会有所帮助和赞赏。因为我相信你可以猜到我的课程比近100个属性所提供的范例更大。大多数都是字符串值,将通过TextBox对象手动输入。我正在尝试创建一个可以被所有TextBox对象调用的例程,从而可以使用该对象的Tag属性来指示我正在尝试设置的类的哪个属性。从那里开始到XML序列化土地。

2 个答案:

答案 0 :(得分:7)

你最内线

info2.SetValue(m_objCompany, objValue, null);

正在尝试在外部对象上设置内部属性(info2)的值。外部对象没有内部对象。

你可能想要的是这样的:

    public void Bar(object m_objCompany)
    {
        foreach (PropertyInfo info in m_objCompany.GetType().GetProperties())
        {
            if (info.PropertyType != typeof(System.String))
            {
                // Somehow create the outer property
                object outerPropertyValue = info.PropertyType.GetConstructor(new Type[] { }).Invoke(new object[] { });

                foreach (PropertyInfo info2 in info.PropertyType.GetProperties())
                {
                    if ("blah" == "blah")
                    {
                        if (info2.CanWrite)
                        {
                            Object innerPropertyValue = Convert.ChangeType("blah", info2.PropertyType);
                            info2.SetValue(outerPropertyValue, innerPropertyValue, null);
                        }
                    }

                }

                info.SetValue(m_objCompany, outerPropertyValue, null);
            }
        }
    }

当遇到要设置的属性时,需要创建该属性(outerPropertyValue),然后设置该属性的属性(通过innerPropertyValue),然后在原始对象(m_objCompany)上设置外部属性。

答案 1 :(得分:6)

这是我用于Reflection的一些代码。在这种情况下,您需要调用SetValue方法。

Reflector.SetValue(TARGET_OBJECT, "Customer.Details.PhoneNumber", "ValueToSet");

UPDATE:添加了缺少的ConversionResult结构。很抱歉遗漏。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Reflection;

namespace YourNamespace
{
  public struct ConversionResult
  {
     public Boolean Success;
     public object ConvertedValue;
  }

  public static class Reflector
  {
    private static BindingFlags DefaultBindings = BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.NonPublic;
    #region Public Methods
    /// <summary>
    /// Execute the "codeToExecute" string on the "source" object
    /// </summary>
    /// <param name="source">Object the code should be executed against</param>
    /// <param name="codeToExecute">Code that should be executed ex. 'Person.Age'</param>
    /// <returns>The result of execute codeToExecute on source</returns>
    public static object GetValue(object source, String codeToExecute)
    {
      ReflectorResult reflectorResult = GetReflectorResult(source, codeToExecute, true, false);
      if (reflectorResult != null)
      {
        return reflectorResult.Value;
      }
      return null;
    }

    /// <summary>
    /// Sets the "source" object to the "value" specified in "codeToExecute"
    /// </summary>
    /// <param name="source">Object the code should be executed against</param>
    /// <param name="codeToExecute">Code that should be executed ex. 'Person.Age'</param>
    /// <param name="value">Value to set the source+codeToExecute to.</param>
    public static Boolean SetValue(object source, String codeToExecute, object value)
    {
      return SetValue(source, codeToExecute, value, false);
    }

    /// <summary>
    /// Sets the "source" object to the "value" specified in "codeToExecute"
    /// </summary>
    /// <param name="source">Object the code should be executed against</param>
    /// <param name="codeToExecute">Code that should be executed ex. 'Person.Age'</param>
    /// <param name="value">Value to set the source+codeToExecute to.</param>
    /// <param name="createIfNotExists">Creates items it cannot find</param>
    public static Boolean SetValue(object source, String codeToExecute, object value, Boolean createIfNotExists)
    {
      Boolean executed = true;

      ReflectorResult reflectorResult = GetReflectorResult(source, codeToExecute, false, createIfNotExists);
      if (reflectorResult != null)
      {
        TypeConverter typeConverter = null;
        PropertyInfo propertyInfo = reflectorResult.MemberInfo as PropertyInfo;
        if (propertyInfo != null)
        {
          if (propertyInfo.CanWrite)
          {
            typeConverter = GetTypeConverter(propertyInfo);

            ConversionResult conversionResult = ConvertValue(value, propertyInfo.PropertyType, typeConverter);
            if (conversionResult.Success)
            {
              propertyInfo.SetValue(reflectorResult.PreviousValue, conversionResult.ConvertedValue, reflectorResult.MemberInfoParameters);
            }
            else
            {
              executed = false;
              PentaLogger.LogVerbose("Invalid value: " + value);
            }
          }
        }
        else
        {
          FieldInfo fieldInfo = reflectorResult.MemberInfo as FieldInfo;
          if (fieldInfo != null)
          {
            typeConverter = GetTypeConverter(fieldInfo);
            ConversionResult conversionResult = ConvertValue(value, fieldInfo.FieldType, typeConverter);
            if (conversionResult.Success)
            {
              fieldInfo.SetValue(reflectorResult.PreviousValue, conversionResult.ConvertedValue);
            }
            else
            {
              executed = false;
              PentaLogger.LogVerbose("Invalid value: " + value);
            }
          }
          else
          {
            // both property and field are invalid
            executed = false;
          }
        }
      }
      else
      {
        executed = false;
      }

      return executed;
    }

    /// <summary>
    /// Sets the "source" object to the "value" specified in "codeToExecute"
    /// </summary>
    /// <param name="source">Object the code should be executed against</param>
    /// <param name="codeToExecute">Code that should be executed ex. 'Person.Age'</param>
    /// <param name="value">Value to set the source+codeToExecute to.</param>
    public static void RunDynamicCode(object source, String codeToExecute)
    {
      GetReflectorResult(source, codeToExecute, true, false);
    }

    /// <summary>
    /// Executes the method on the "source" object with the passed parameters
    /// </summary>
    /// <param name="source">Object the code should be executed against</param>
    /// <param name="methodName">Method to call</param>
    /// <param name="parameters">Method Parameters</param>
    public static object ExecuteMethod(object source, String methodName, object[] parameters)
    {
      if (parameters == null)
      {
        parameters = new object[0];
      }

      MethodInfo[] methodInfos = GetMethods(source, methodName);

      foreach (MethodInfo methodInfo in methodInfos)
      {
        object[] convertedParameters = GetParameters(methodInfo, parameters);
        if (convertedParameters != null)
        {
          return methodInfo.Invoke(source, convertedParameters);
        }
      }
      return null;
    }

    /// <summary>
    /// Executes the method on the "source" object with the passed parameters
    /// </summary>
    /// <param name="source">Object the code should be executed against</param>
    /// <param name="methodName">Method to call</param>
    /// <param name="parameter">Method Parameter</param>
    public static object ExecuteMethod(object source, String methodName, object parameter)
    {
      return ExecuteMethod(source, methodName, new object[] { parameter });
    }

    /// <summary>
    /// Executes the method on the "source" object with no parameters
    /// </summary>
    /// <param name="source">Object the code should be executed against</param>
    /// <param name="methodName">Method to call</param>
    public static object ExecuteMethod(object source, String methodName)
    {
      return ExecuteMethod(source, methodName, null);
    }

    /// <summary>
    /// Copies all public properties and fields from source to target
    /// </summary>
    /// <param name="source"></param>
    /// <param name="target"></param>
    public static void CopyObject(object source, object target)
    {
      if (source != null && target != null)
      {
        Type targetType = target.GetType();
        Type sourceType = source.GetType();

        PropertyInfo[] properties = sourceType.GetProperties(DefaultBindings);
        foreach (PropertyInfo sourceProperty in properties)
        {
          PropertyInfo targetProperty = targetType.GetProperty(sourceProperty.Name, sourceProperty.PropertyType);
          if (targetProperty != null && targetProperty.CanRead && targetProperty.CanWrite)
          {
            object value = sourceProperty.GetValue(source, null);
            targetProperty.SetValue(target, value, null);
          }
        }

        FieldInfo[] fields = sourceType.GetFields(DefaultBindings);
        foreach (FieldInfo sourceField in fields)
        {
          FieldInfo targetField = targetType.GetField(sourceField.Name);
          if (targetField != null && targetField.IsPublic)
          {
            object value = sourceField.GetValue(source);
            targetField.SetValue(target, value);
          }
        }
      }
    }

    /// <summary>
    /// Convert the object to the correct type
    /// </summary>
    /// <param name="value">Value to convert</param>
    /// <param name="type">Type to convert to</param>
    /// <returns>Converted value</returns>
    public static ConversionResult ConvertValue(object value, Type type, TypeConverter typeConverter)
    {
      ConversionResult conversionResult = new ConversionResult();
      conversionResult.Success = false;
      if (value != null && type != null)
      {
        Type objectType = value.GetType();
        if (objectType == type)
        {
          conversionResult.Success = true;
          conversionResult.ConvertedValue = value;
        }
        else
        {
          // If there is an explicit type converter use it
          if (typeConverter != null && typeConverter.CanConvertFrom(objectType))
          {
            try
            {
              conversionResult.ConvertedValue = typeConverter.ConvertFrom(value);
              conversionResult.Success = true;
            }
            catch (FormatException) { }
            catch (Exception e)
            {
              if (!(e.InnerException is FormatException))
              {
                throw;
              }
            }
          }
          else
          {
            try
            {
              conversionResult.ConvertedValue = Convert.ChangeType(value, type, CultureInfo.CurrentCulture);
              conversionResult.Success = true;
            }
            catch (InvalidCastException) { }
          }
        }
      }
      return conversionResult;
    }

    public static Boolean CanCreateObect(String classPath, Assembly assembly, params object[] parameters)
    {
      Boolean canCreate = false;
      Type type = Type.GetType(classPath);
      if (type == null)
      {
        String pathWithAssembly = classPath + ", " + assembly.FullName;
        type = Type.GetType(pathWithAssembly);
      }

      if (type != null)
      {
        foreach (ConstructorInfo ci in type.GetConstructors())
        {
          if (ci.IsPublic)
          {
            ParameterInfo[] constructorParameters = ci.GetParameters();
            if (constructorParameters.Length == parameters.Length)
            {
              for(Int32 i=0; i<constructorParameters.Length; i++)
              {                
                object parameter = parameters[i];
                if(parameter == null)
                {
                  continue;
                }

                ParameterInfo pi = constructorParameters[i];
                if (!pi.ParameterType.IsAssignableFrom(parameter.GetType()))
                {
                  break;
                }
              }
              canCreate = true;
              break;
            }
          }  
        }       
      }
      return canCreate;
    }

    public static object CreateObject(String classPath, Assembly assembly, params object[] parameters)
    {
      Type type = Type.GetType(classPath);
      if (type == null)
      {
        String pathWithAssembly = classPath + ", " + assembly.FullName;
        type = Type.GetType(pathWithAssembly);
      }

      if (type == null)
      {
        return null;
      }
      return Activator.CreateInstance(type, parameters);
    }
    #endregion

    #region Private Methods
    private static ReflectorResult GetReflectorResult(object source, String codeToExecute, bool getLastValue, bool createIfNotExists)
    {
      ReflectorResult result = new ReflectorResult(source);

      try
      {
        // Split the code into usable fragments
        String[] codeFragments = SplitCodeArray(codeToExecute);
        for (Int32 i = 0; i < codeFragments.Length; i++)
        {
          // if the value is null we cannot go any deeper so don't waste your time
          if (result.Value == null)
          {
            return result;
          }

          String codeFragment = codeFragments[i];
          result.PreviousValue = result.Value;

          if (codeFragment.Contains("]"))
          {
            ProcessArray(result, codeFragment, createIfNotExists);
          }
          else if (codeFragment.Contains(")"))
          {
            ProcessMethod(result, codeFragment);
          }
          else
          {
            // For set properties we do not need the last value
            bool retrieveValue = getLastValue;
            if (!retrieveValue)
            {
              // If this is not the last one in the array, get it anyway
              retrieveValue = i + 1 != codeFragments.Length;
            }
            ProcessProperty(result, codeFragment, retrieveValue);
          }
        }
      }
      catch (InvalidCodeFragmentException ex)
      {
        PentaLogger.LogVerbose("Invalid Property: '" + codeToExecute + "' Invalid Fragment: '" + ex.Message + "'");
      }

      return result;
    }

    private static String[] SplitCodeArray(String codeToExecute)
    {
      List<String> items = new List<String>();

      Int32 parenAndbracketCount = 0;
      String buffer = "";
      foreach (Char c in codeToExecute.ToCharArray())
      {
        if (c == '.')
        {
          if (buffer.Length > 0)
          {
            items.Add(buffer);
            buffer = "";
          }
          continue;
        }
        else if (c == '[')
        {
          parenAndbracketCount++;
          if (buffer.Length > 0)
          {
            items.Add(buffer);
          }
          buffer = c.ToString();
        }
        else if (c == ']' || c == ')')
        {
          parenAndbracketCount--;
          buffer += c;
          if (buffer.Length > 0)
          {
            items.Add(buffer);
            buffer = "";
          }
        }
        else if (Char.IsWhiteSpace(c) || Char.IsControl(c))
        {
          if (parenAndbracketCount == 0)
          {
            // Skip it
            continue;
          }
          else
          {
            buffer += c;
          }
        }
        else if (c == '(')
        {
          parenAndbracketCount++;
          buffer += c;
        }
        else
        {
          buffer += c;
        }
      }
      if (buffer.Length > 0)
      {
        items.Add(buffer);
      }
      return items.ToArray();
    }

    private static object[] GetParameters(String codeFragment, MemberInfo memberInfo)
    {
      String parameters = SplitParametersFromMethod(codeFragment);
      if (String.IsNullOrEmpty(parameters))
        return new object[0];

      object[] parameterArray = parameters.Split(',');
      return GetParameters(memberInfo, parameterArray);
    }

    private static object[] GetParameters(MemberInfo memberInfo, object[] parameterArray)
    {
      ParameterInfo[] parameterInfo = null;
      TypeConverter typeConverter = null;

      PropertyInfo propertyInfo = memberInfo as PropertyInfo;
      if (propertyInfo != null)
      {
        parameterInfo = propertyInfo.GetIndexParameters();
        typeConverter = GetTypeConverter(parameterInfo[0]);
      }
      else
      {
        MethodInfo methodInfo = memberInfo as MethodInfo;
        if (methodInfo != null)
        {
          parameterInfo = methodInfo.GetParameters();
        }
      }

      if (parameterInfo == null)
      {
        return null;
      }

      object[] returnParameters = new object[parameterInfo.Length];
      for (Int32 i = 0; i < parameterArray.Length; i++)
      {
        ConversionResult converstionResult = ConvertValue(parameterArray[i], parameterInfo[i].ParameterType, typeConverter);
        if (converstionResult.Success)
        {
          returnParameters[i] = converstionResult.ConvertedValue;
        }
        else
        {
          return null;
        }
      }
      return returnParameters;
    }

    private static TypeConverter GetTypeConverter(MemberInfo memberInfo, Type targetType)
    {
      object[] typeConverters = memberInfo.GetCustomAttributes(typeof(TypeConverterAttribute), true);
      if (typeConverters.Length > 0)
      {
        TypeConverterAttribute typeConverterAttribute = (TypeConverterAttribute)typeConverters[0];
        Type typeFromName = Type.GetType(typeConverterAttribute.ConverterTypeName);
        if ((typeFromName != null) && typeof(TypeConverter).IsAssignableFrom(typeFromName))
        {
          return (TypeConverter)Activator.CreateInstance(typeFromName);
        }
      }
      return TypeDescriptor.GetConverter(targetType);
    }

    private static TypeConverter GetTypeConverter(PropertyInfo propertyInfo)
    {
      return GetTypeConverter(propertyInfo, propertyInfo.PropertyType);
    }

    private static TypeConverter GetTypeConverter(FieldInfo fieldInfo)
    {
      return GetTypeConverter(fieldInfo, fieldInfo.FieldType);
    }

    private static TypeConverter GetTypeConverter(ParameterInfo parameterInfo)
    {
      return GetTypeConverter(parameterInfo.Member, parameterInfo.ParameterType);
    }

    private static ArrayDefinition GetArrayDefinition(object value, String codeToExecute)
    {
      // All IList classes have an Item property except for System.Array.
      List<MemberInfo> retrieveMemberInfos = new List<MemberInfo>();
      foreach (PropertyInfo propertyInfo in value.GetType().GetProperties(DefaultBindings))
      {
        if (propertyInfo.Name == "Item")
        {
          retrieveMemberInfos.Add(propertyInfo);
        }
      }

      if (retrieveMemberInfos.Count == 0)
      {
        // We didn't find any Item properties so this is probably an Array. Use the GetValue method
        foreach (MethodInfo methodInfo in value.GetType().GetMethods(DefaultBindings))
        {
          if (methodInfo.Name == "GetValue")
          {
            retrieveMemberInfos.Add(methodInfo);
          }
        }
      }

      // Some members have overloaded this[] methods. Find the correct method.
      foreach (MemberInfo memberInfo in retrieveMemberInfos)
      {
        object[] parameters = GetParameters(codeToExecute, memberInfo);
        if (parameters != null)
        {
          ArrayDefinition arrayDefinition = new ArrayDefinition();
          arrayDefinition.Parameters = parameters;
          arrayDefinition.RetrieveMemberInfo = memberInfo;
          return arrayDefinition;
        }
      }
      return null;
    }

    private static void ProcessArray(ReflectorResult result, String codeFragment, Boolean createIfNotExists)
    {
      Int32 failCount = 0;
      ArrayDefinition arrayDefinition = GetArrayDefinition(result.Value, codeFragment);
      if (arrayDefinition != null)
      {
        // If this is anything but System.Array we need to call a Property
        PropertyInfo propertyInfo = arrayDefinition.RetrieveMemberInfo as PropertyInfo;
        if (propertyInfo != null)
        {
        SetPropertyInfoValue:
          try
          {
            object value = propertyInfo.GetValue(result.Value, arrayDefinition.Parameters);
            result.SetResult(value, propertyInfo, arrayDefinition.Parameters);
          }
          catch (TargetInvocationException ex)
          {
            failCount++;
            if (ex.InnerException is ArgumentOutOfRangeException && failCount == 1 && createIfNotExists)
            {
              if (CreateArrayItem(result, arrayDefinition))
              {
                goto SetPropertyInfoValue;
              }
            }

            // Tried to fix it but failed. Blow up
            result.Clear();
            throw new InvalidCodeFragmentException(codeFragment);
          }
        }
        else
        {
          // System.Array has a Method to call
          MethodInfo methodInfo = arrayDefinition.RetrieveMemberInfo as MethodInfo;
          if (methodInfo != null)
          {
            try
            {
              // We can't support dynamically creating array items
              object value = methodInfo.Invoke(result.Value, arrayDefinition.Parameters);
              result.SetResult(value, methodInfo, arrayDefinition.Parameters);
            }
            catch (TargetInvocationException)
            {
              result.Clear();
              throw new InvalidCodeFragmentException(codeFragment);
            }
          }
        }
      }
      else
      {
        result.Clear();
        throw new InvalidCodeFragmentException(codeFragment);
      }
    }

    private static Boolean CreateArrayItem(ReflectorResult result, ArrayDefinition arrayDefinition)
    {
      Type resultType = result.Value.GetType();
      Type containedType = null;
      if (resultType.IsArray)
      {
        containedType = resultType.GetElementType();
      }
      else
      {
        containedType = resultType.GetGenericArguments()[0];
      }

      object newInstance = Activator.CreateInstance(containedType);
      if (!resultType.IsArray)
      {
        MethodInfo[] methods = GetMethods(result.Value, "Insert");
        foreach (MethodInfo methodInfo in methods)
        {
          object[] temp = new object[arrayDefinition.Parameters.Length + 1];
          arrayDefinition.Parameters.CopyTo(temp, 0);
          temp[arrayDefinition.Parameters.Length] = newInstance;

          object[] parameters = GetParameters(methodInfo, temp);
          if (parameters != null)
          {
            methodInfo.Invoke(result.Value, parameters);
            return true;
          }
        }
      }
      return false;
    }

    private static void ProcessProperty(ReflectorResult result, String codeFragment, bool retrieveValue)
    {
      // This is just a regular property
      PropertyInfo propertyInfo = result.Value.GetType().GetProperty(codeFragment, DefaultBindings);
      if (propertyInfo != null)
      {
        object value = result.Value;
        if (retrieveValue)
        {
          value = propertyInfo.GetValue(result.Value, null);
          result.SetResult(value, propertyInfo, null);
        }
        result.SetResult(value, propertyInfo, null);
      }
      else
      {
        // Maybe it is a field
        FieldInfo fieldInfo = result.Value.GetType().GetField(codeFragment, DefaultBindings);

        if (fieldInfo != null)
        {
          object value = result.Value;
          if (retrieveValue)
          {
            value = fieldInfo.GetValue(result.Value);
          }
          result.SetResult(value, fieldInfo, null);
        }
        else
        {
          // This item is missing, log it and set the value to null
          result.Clear();
          throw new InvalidCodeFragmentException(codeFragment);
        }
      }
    }

    private static void ProcessMethod(ReflectorResult result, String codeFragment)
    {
      // This is just a regular property
      String methodName = codeFragment.Substring(0, codeFragment.IndexOf('('));
      MethodInfo[] methodInfos = GetMethods(result.Value, methodName);

      foreach (MethodInfo methodInfo in methodInfos)
      {
        object[] parameters = GetParameters(codeFragment, methodInfo);
        if (parameters != null)
        {
          object value = methodInfo.Invoke(result.Value, parameters);
          result.SetResult(value, null, null);
          break;
        }
      }
    }

    private static String SplitParametersFromMethod(String codeFragment)
    {
      char startCharacter = '[';
      char endCharacter = ']';

      if (codeFragment.EndsWith(")", StringComparison.CurrentCulture))
      {
        // This is a function
        startCharacter = '(';
        endCharacter = ')';
      }

      Int32 startParam = codeFragment.IndexOf(startCharacter) + 1;
      if (startParam < 1)
        return null;

      Int32 endParam = codeFragment.IndexOf(endCharacter);
      if (endParam < 0)
        return null;

      return codeFragment.Substring(startParam, endParam - startParam).Trim();
    }

    private static MethodInfo[] GetMethods(object value, String methodName)
    {
      if (String.IsNullOrEmpty(methodName))
      {
        throw new ArgumentNullException("methodName");
      }

      if (value == null)
      {
        return new MethodInfo[0];
      }

      List<MethodInfo> methodInfos = new List<MethodInfo>();
      foreach (MethodInfo methodInfo in value.GetType().GetMethods(DefaultBindings))
      {
        if (methodInfo.Name == methodName)
        {
          methodInfos.Add(methodInfo);
        }
      }
      return methodInfos.ToArray();
    }
    #endregion

    #region Helper Classes
    private class ArrayDefinition
    {
      public MemberInfo RetrieveMemberInfo { get; set; }

      public object[] Parameters { get; set; }
    }

    private class ReflectorResult
    {
      public ReflectorResult(object startValue)
      {
        SetResult(startValue, null, null);
      }
      public MemberInfo MemberInfo { get; private set; }
      public object[] MemberInfoParameters { get; private set; }
      public object PreviousValue { get; set; }
      public object Value { get; private set; }

      public void SetResult(object value, MemberInfo memberInfo, object[] memberInfoParameters)
      {
        Value = value;
        MemberInfo = memberInfo;
        MemberInfoParameters = memberInfoParameters;
      }

      public void Clear()
      {
        MemberInfo = null;
        Value = null;
        PreviousValue = null;
      }
    }

    [Serializable]
    [SuppressMessage("Microsoft.Design", "CA1064:ExceptionsShouldBePublic")]
    [SuppressMessage("Microsoft.Design", "CA1032:ImplementStandardExceptionConstructors")]
    private class InvalidCodeFragmentException : Exception
    {
      public InvalidCodeFragmentException(String invalidFragment)
        : base(invalidFragment)
      {

      }
    }
    #endregion
  }
}