// Constructors

        public QueryParameterIdentity(TypeMapping mapping, object closureObject, string fieldName, QueryParameterBindingType bindingType)
        {
            ArgumentValidator.EnsureArgumentNotNull(mapping, "mapping");
            ArgumentValidator.EnsureArgumentNotNull(closureObject, "closureObject");
            ArgumentValidator.EnsureArgumentNotNullOrEmpty(fieldName, "fieldName");

            Mapping       = mapping;
            ClosureObject = closureObject;
            FieldName     = fieldName;
            BindingType   = bindingType;
        }
        // Constructors

        private QueryParameterBinding(TypeMapping typeMapping, Func <ParameterContext, object> valueAccessor,
                                      ParameterTransmissionType transmissionType, QueryParameterBindingType bindingType)
            : base(typeMapping, transmissionType)
        {
            ArgumentValidator.EnsureArgumentNotNull(valueAccessor, "valueAccessor");

            switch (bindingType)
            {
            case QueryParameterBindingType.Regular:
            case QueryParameterBindingType.SmartNull:
                ArgumentValidator.EnsureArgumentNotNull(typeMapping, "typeMapping");
                break;
            }

            ValueAccessor = valueAccessor;
            BindingType   = bindingType;
        }
 public QueryParameterBinding(TypeMapping typeMapping, Func <ParameterContext, object> valueAccessor, QueryParameterBindingType bindingType)
     : this(typeMapping, valueAccessor, ParameterTransmissionType.Regular, bindingType)
 {
 }
        private QueryParameterBinding RegisterParameterBinding(TypeMapping mapping,
                                                               Expression <Func <object> > accessor, QueryParameterBindingType bindingType)
        {
            QueryParameterBinding result;
            var identity = GetParameterIdentity(mapping, accessor, bindingType);

            if (identity == null)
            {
                result = new QueryParameterBinding(mapping, accessor.CachingCompile(), bindingType);
                otherBindings.Add(result);
                return(result);
            }

            if (bindingsWithIdentity.TryGetValue(identity, out result))
            {
                return(result);
            }

            result = new QueryParameterBinding(mapping, accessor.CachingCompile(), bindingType);
            bindingsWithIdentity.Add(identity, result);
            return(result);
        }
        private QueryParameterIdentity GetParameterIdentity(TypeMapping mapping,
                                                            Expression <Func <object> > accessor, QueryParameterBindingType bindingType)
        {
            var expression = accessor.Body;

            // Strip cast to object
            if (expression.NodeType == ExpressionType.Convert)
            {
                expression = ((UnaryExpression)expression).Operand;
            }

            // Check for closure member access
            if (expression.NodeType != ExpressionType.MemberAccess)
            {
                return(null);
            }

            var memberAccess = (MemberExpression)expression;
            var operand      = memberAccess.Expression;

            if (operand == null || !operand.Type.IsClosure())
            {
                return(null);
            }
            var fieldName = memberAccess.Member.Name;

            // Check for raw closure
            if (operand.NodeType == ExpressionType.Constant)
            {
                var closureObject = ((ConstantExpression)operand).Value;
                return(new QueryParameterIdentity(mapping, closureObject, fieldName, bindingType));
            }

            // Check for parameterized closure
            if (operand.NodeType == ExpressionType.MemberAccess)
            {
                memberAccess = (MemberExpression)operand;
                operand      = memberAccess.Expression;
                var isParameter = operand != null &&
                                  operand.NodeType == ExpressionType.Constant &&
                                  typeof(Parameter).IsAssignableFrom(operand.Type) &&
                                  memberAccess.Member.Name == "Value";
                if (isParameter)
                {
                    var parameterObject = ((ConstantExpression)operand).Value;
                    return(new QueryParameterIdentity(mapping, parameterObject, fieldName, bindingType));
                }
            }

            return(null);
        }
        private static QueryParameterIdentity GetParameterIdentity(TypeMapping mapping,
                                                                   Expression <Func <ParameterContext, object> > accessor, QueryParameterBindingType bindingType)
        {
            var expression = accessor.Body;

            // Strip cast to object
            if (expression.NodeType == ExpressionType.Convert)
            {
                expression = ((UnaryExpression)expression).Operand;
            }

            // Check for closure member access
            if (expression.NodeType != ExpressionType.MemberAccess)
            {
                return(null);
            }

            var memberAccess = (MemberExpression)expression;
            var operand      = memberAccess.Expression;

            if (operand == null || !operand.Type.IsClosure())
            {
                return(null);
            }

            var fieldName = memberAccess.Member.Name;

            // Check for raw closure
            if (operand.NodeType == ExpressionType.Constant)
            {
                var closureObject = ((ConstantExpression)operand).Value;
                return(new QueryParameterIdentity(mapping, closureObject, fieldName, bindingType));
            }

            // Check for parameterized closure
            if (operand.NodeType == ExpressionType.Call)
            {
                var callExpression = (MethodCallExpression)operand;
                if (string.Equals(callExpression.Method.Name, nameof(ParameterContext.GetValue), StringComparison.Ordinal))
                {
                    operand = callExpression.Object;
                    if (operand != null && WellKnownOrmTypes.ParameterContext == operand.Type)
                    {
                        operand = callExpression.Arguments[0];
                    }
                }

                var isParameter = operand != null && operand.NodeType == ExpressionType.Constant;
                if (isParameter)
                {
                    var parameterObject = ((ConstantExpression)operand).Value;
                    return(new QueryParameterIdentity(mapping, parameterObject, fieldName, bindingType));
                }
            }

            return(null);
        }