/// <summary> /// Determine if the binary expression is comparing the key value against a constant /// using CompareTo. /// </summary> /// <param name="expression">The expression.</param> /// <param name="keyMemberInfo">The name of the parameter key.</param> /// <param name="value">Returns the constant being compared against.</param> /// <param name="expressionType">Returns the type of the comparison.</param> /// <returns>True if this expression is comparing the key value against a constant.</returns> private static bool IsCompareToExpression(BinaryExpression expression, MemberInfo keyMemberInfo, out TKey value, out ExpressionType expressionType) { // CompareTo is only guaranteed to return <0, 0 or >0 so allowing for // comparisons with values other than 0 is complicated/subtle. // One way this could be expanded is by recognizing "< 1", and "> -1" as well. if (IsCompareTo(expression.Left, keyMemberInfo, out value)) { int comparison; if (ConstantExpressionEvaluator <int> .TryGetConstantExpression(expression.Right, out comparison) && 0 == comparison) { expressionType = expression.NodeType; return(true); } } if (IsCompareTo(expression.Right, keyMemberInfo, out value)) { int comparison; if (ConstantExpressionEvaluator <int> .TryGetConstantExpression(expression.Left, out comparison) && 0 == comparison) { expressionType = GetReverseExpressionType(expression.NodeType); return(true); } } expressionType = ExpressionType.Equal; value = default(TKey); return(false); }
/// <summary> /// Determine if the binary expression is comparing the key value against a string /// using the simplest (two-argument) form of String.Compare. /// </summary> /// <param name="expression">The expression.</param> /// <param name="keyMemberInfo">The name of the parameter key.</param> /// <param name="value">Returns the constant being compared against.</param> /// <param name="expressionType">Returns the type of the comparison.</param> /// <returns>True if this expression is comparing the key value against a constant string.</returns> private static bool IsStringComparisonExpression(BinaryExpression expression, MemberInfo keyMemberInfo, out TKey value, out ExpressionType expressionType) { Debug.Assert(typeof(string) == typeof(TKey), "This method should only be called for string keys"); // CompareTo is only guaranteed to return <0, 0 or >0 so allowing for // comparisons with values other than 0 is complicated/subtle. // One way this could be expanded is by recognizing "< 1", and "> -1" as well. // // This code is tricky because there are 4 possibilities and we want // to turn them into a canonical form. In the first two cases we do // not reverse the sense of the comparison: // 1. String.Compare(Key, "m") < 0 // 2. 0 < String.Compare("m", Key) // In the second two cases we do reverse the sense of the comparison: // 3. String.Compare("m", Key) > 0 // 4. 0 > String.Compare(Key, "m") if (IsStringCompare(expression.Left, keyMemberInfo, out value)) { int comparison; if (ConstantExpressionEvaluator <int> .TryGetConstantExpression(expression.Right, out comparison) && 0 == comparison) { expressionType = expression.NodeType; return(true); } } else if (IsStringCompareReversed(expression.Right, keyMemberInfo, out value)) { int comparison; if (ConstantExpressionEvaluator <int> .TryGetConstantExpression(expression.Left, out comparison) && 0 == comparison) { expressionType = expression.NodeType; return(true); } } else if (IsStringCompareReversed(expression.Left, keyMemberInfo, out value)) { int comparison; if (ConstantExpressionEvaluator <int> .TryGetConstantExpression(expression.Right, out comparison) && 0 == comparison) { expressionType = GetReverseExpressionType(expression.NodeType); return(true); } } else if (IsStringCompare(expression.Right, keyMemberInfo, out value)) { int comparison; if (ConstantExpressionEvaluator <int> .TryGetConstantExpression(expression.Left, out comparison) && 0 == comparison) { expressionType = GetReverseExpressionType(expression.NodeType); return(true); } } expressionType = ExpressionType.Equal; value = default(TKey); return(false); }
/// <summary> /// Determine if the MethodCallExpression is a key comparison method, and /// return the index range if it is. /// </summary> /// <param name="methodCall">The method call expression.</param> /// <param name="keyMemberInfo">The name of the parameter member that is the key.</param> /// <param name="keyRange">Returns the key range if this is a key comparison method.</param> /// <returns>True if the method is a key comparison method.</returns> private static bool IsComparisonMethod(MethodCallExpression methodCall, MemberInfo keyMemberInfo, out KeyRange <TKey> keyRange) { if (null != methodCall.Object && IsKeyAccess(methodCall.Object, keyMemberInfo)) { TKey value; // TKey.Equals if ((equalsMethod == methodCall.Method) && ConstantExpressionEvaluator <TKey> .TryGetConstantExpression(methodCall.Arguments[0], out value)) { keyRange = new KeyRange <TKey>(Key <TKey> .CreateKey(value, true), Key <TKey> .CreateKey(value, true)); return(true); } } if (typeof(TKey) == typeof(string)) { if (null != methodCall.Object && IsKeyAccess(methodCall.Object, keyMemberInfo)) { TKey value; // String.StartsWith if (StringExpressionEvaluatorHelper.StringStartWithMethod == methodCall.Method && ConstantExpressionEvaluator <TKey> .TryGetConstantExpression(methodCall.Arguments[0], out value)) { // Lower range is just the string, upper range is the prefix keyRange = new KeyRange <TKey>(Key <TKey> .CreateKey(value, true), Key <TKey> .CreatePrefixKey(value)); return(true); } } else if (null == methodCall.Object) { // Static String.Equals if (StringExpressionEvaluatorHelper.StringStaticEqualsMethod == methodCall.Method) { TKey value; if ((IsKeyAccess(methodCall.Arguments[0], keyMemberInfo) && ConstantExpressionEvaluator <TKey> .TryGetConstantExpression(methodCall.Arguments[1], out value)) || (IsKeyAccess(methodCall.Arguments[1], keyMemberInfo) && ConstantExpressionEvaluator <TKey> .TryGetConstantExpression(methodCall.Arguments[0], out value))) { keyRange = new KeyRange <TKey>(Key <TKey> .CreateKey(value, true), Key <TKey> .CreateKey(value, true)); return(true); } } } } keyRange = null; return(false); }
/// <summary> /// Determine if the expression is a call to String.Compare(value, key). /// </summary> /// <param name="expression">The expression to examine.</param> /// <param name="keyMemberInfo">The name of the key member.</param> /// <param name="value">Returns the string value being compared against.</param> /// <returns> /// True if the expression is a call to String.Compare(value, key). /// </returns> private static bool IsStringCompareReversed(Expression expression, MemberInfo keyMemberInfo, out TKey value) { if (expression is MethodCallExpression) { MethodCallExpression methodCall = (MethodCallExpression)expression; if (methodCall.Method == StringExpressionEvaluatorHelper.StringStaticCompareMethod && IsKeyAccess(methodCall.Arguments[1], keyMemberInfo)) { return(ConstantExpressionEvaluator <TKey> .TryGetConstantExpression(methodCall.Arguments[0], out value)); } } value = default(TKey); return(false); }
/// <summary> /// Determine if the expression is a call to [param].[member].CompareTo(value). /// </summary> /// <param name="expression">The expression to examine.</param> /// <param name="keyMemberInfo">The name of the key member.</param> /// <param name="value">Returns the string value being compared against.</param> /// <returns> /// True if the expression is a call to parameter.keyMember.CompareTo(value). /// </returns> private static bool IsCompareTo(Expression expression, MemberInfo keyMemberInfo, out TKey value) { if (expression is MethodCallExpression) { MethodCallExpression methodCall = (MethodCallExpression)expression; if (methodCall.Method == compareToMethod && null != methodCall.Object && IsKeyAccess(methodCall.Object, keyMemberInfo)) { return(ConstantExpressionEvaluator <TKey> .TryGetConstantExpression(methodCall.Arguments[0], out value)); } } value = default(TKey); return(false); }
/// <summary> /// Determine if the binary expression is comparing the key value against a constant. /// </summary> /// <param name="expression">The expression.</param> /// <param name="keyMemberInfo">The name of the parameter key.</param> /// <param name="value">Returns the constant being compared against.</param> /// <param name="expressionType">Returns the type of the comparison.</param> /// <returns>True if this expression is comparing the key value against a constant.</returns> private static bool IsSimpleComparisonExpression(BinaryExpression expression, MemberInfo keyMemberInfo, out TKey value, out ExpressionType expressionType) { if (IsKeyAccess(expression.Left, keyMemberInfo) && ConstantExpressionEvaluator <TKey> .TryGetConstantExpression(expression.Right, out value)) { expressionType = expression.NodeType; return(true); } if (IsKeyAccess(expression.Right, keyMemberInfo) && ConstantExpressionEvaluator <TKey> .TryGetConstantExpression(expression.Left, out value)) { // The access is on the right so we have to switch the comparison type expressionType = GetReverseExpressionType(expression.NodeType); return(true); } expressionType = ExpressionType.Equal; value = default(TKey); return(false); }