/// <summary>
    /// Constructs a <see cref="LambdaExpression"/> that is able to extract a specific simple <paramref name="searchedExpression"/> from a 
    /// complex <paramref name="fullExpression"/>.
    /// </summary>
    /// <param name="searchedExpression">The expression an accessor to which should be created.</param>
    /// <param name="fullExpression">The full expression containing the <paramref name="searchedExpression"/>.</param>
    /// <param name="inputParameter">The input parameter to be used by the resulting lambda. Its type must match the type of <paramref name="fullExpression"/>.</param>
    /// <remarks>The <see cref="AccessorFindingExpressionVisitor"/> compares the <paramref name="searchedExpression"/> via reference equality,
    /// which means that exactly the same expression reference must be contained by <paramref name="fullExpression"/> for the visitor to return the
    /// expected result. In addition, the visitor can only provide accessors for expressions nested in <see cref="NewExpression"/> or 
    /// <see cref="MemberInitExpression"/>.</remarks>
    /// <returns>A <see cref="LambdaExpression"/> acting as an accessor for the <paramref name="searchedExpression"/> when an input matching 
    /// <paramref name="fullExpression"/> is given.
    /// </returns>
    public static LambdaExpression FindAccessorLambda (Expression searchedExpression, Expression fullExpression, ParameterExpression inputParameter)
    {
      ArgumentUtility.CheckNotNull ("searchedExpression", searchedExpression);
      ArgumentUtility.CheckNotNull ("fullExpression", fullExpression);
      ArgumentUtility.CheckNotNull ("inputParameter", inputParameter);

      if (inputParameter.Type != fullExpression.Type)
      {
        throw new ArgumentException (
            string.Format ("The inputParameter's type '{0}' must match the fullExpression's type '{1}'.", inputParameter.Type, fullExpression.Type),
            "inputParameter");
      }

      var visitor = new AccessorFindingExpressionVisitor (searchedExpression, inputParameter);
      visitor.Visit (fullExpression);

      if (visitor.AccessorPath != null)
        return visitor.AccessorPath;
      else
      {
        var message = string.Format (
            "The given expression '{0}' does not contain the searched expression '{1}' in a nested NewExpression with member assignments or a "
                + "MemberBindingExpression.",
            fullExpression.BuildString(),
            searchedExpression.BuildString());
        throw new ArgumentException (message, "fullExpression");
      }
    }
        /// <summary>
        /// Constructs a <see cref="LambdaExpression"/> that is able to extract a specific simple <paramref name="searchedExpression"/> from a
        /// complex <paramref name="fullExpression"/>.
        /// </summary>
        /// <param name="searchedExpression">The expression an accessor to which should be created.</param>
        /// <param name="fullExpression">The full expression containing the <paramref name="searchedExpression"/>.</param>
        /// <param name="inputParameter">The input parameter to be used by the resulting lambda. Its type must match the type of <paramref name="fullExpression"/>.</param>
        /// <remarks>The <see cref="AccessorFindingExpressionVisitor"/> compares the <paramref name="searchedExpression"/> via reference equality,
        /// which means that exactly the same expression reference must be contained by <paramref name="fullExpression"/> for the visitor to return the
        /// expected result. In addition, the visitor can only provide accessors for expressions nested in <see cref="NewExpression"/> or
        /// <see cref="MemberInitExpression"/>.</remarks>
        /// <returns>A <see cref="LambdaExpression"/> acting as an accessor for the <paramref name="searchedExpression"/> when an input matching
        /// <paramref name="fullExpression"/> is given.
        /// </returns>
        public static LambdaExpression FindAccessorLambda(Expression searchedExpression, Expression fullExpression, ParameterExpression inputParameter)
        {
            ArgumentUtility.CheckNotNull("searchedExpression", searchedExpression);
            ArgumentUtility.CheckNotNull("fullExpression", fullExpression);
            ArgumentUtility.CheckNotNull("inputParameter", inputParameter);

            if (inputParameter.Type != fullExpression.Type)
            {
                throw new ArgumentException(
                          string.Format("The inputParameter's type '{0}' must match the fullExpression's type '{1}'.", inputParameter.Type, fullExpression.Type),
                          "inputParameter");
            }

            var visitor = new AccessorFindingExpressionVisitor(searchedExpression, inputParameter);

            visitor.Visit(fullExpression);

            if (visitor.AccessorPath != null)
            {
                return(visitor.AccessorPath);
            }
            else
            {
                var message = string.Format(
                    "The given expression '{0}' does not contain the searched expression '{1}' in a nested NewExpression with member assignments or a "
                    + "MemberBindingExpression.",
                    fullExpression.BuildString(),
                    searchedExpression.BuildString());
                throw new ArgumentException(message, "fullExpression");
            }
        }
        protected internal override Expression VisitQuerySourceReference(QuerySourceReferenceExpression expression)
        {
            ArgumentUtility.CheckNotNull("expression", expression);

            try
            {
                var accessorLambda = AccessorFindingExpressionVisitor.FindAccessorLambda(expression, _itemExpression, _lambdaParameter);
                return(accessorLambda.Body);
            }
            catch (ArgumentException ex)
            {
                var message = string.Format(
                    "Cannot create a LambdaExpression that retrieves the value of '{0}' from items with a structure of '{1}'. The item expression does not "
                    + "contain the value or it is too complex.",
                    expression.BuildString(),
                    _itemExpression.BuildString());
                throw new InvalidOperationException(message, ex);
            }
        }