Skip to content

Instantly share code, notes, and snippets.

@csuzw
Last active August 29, 2015 14:17
Show Gist options
  • Save csuzw/9c027eed741db0f137f0 to your computer and use it in GitHub Desktop.
Save csuzw/9c027eed741db0f137f0 to your computer and use it in GitHub Desktop.
MemberInfo for non-Member expressions
/// <summary>
/// Crude but effective for my requirements.
/// </summary>
public class ExpressionMemberInfo<T, TProperty> : MemberInfo
{
private static readonly Dictionary<ExpressionType, string> _operatorDescriptions = new Dictionary<ExpressionType, string>
{
{ ExpressionType.Add, "+" },
{ ExpressionType.AddAssign, "+" },
{ ExpressionType.AddAssignChecked, "+" },
{ ExpressionType.AddChecked, "+" },
{ ExpressionType.And, "&" },
{ ExpressionType.AndAlso, "&&" },
{ ExpressionType.AndAssign, "&" },
{ ExpressionType.Decrement, "-" },
{ ExpressionType.Divide, "/" },
{ ExpressionType.DivideAssign, "/" },
{ ExpressionType.ExclusiveOr, "^" },
{ ExpressionType.ExclusiveOrAssign, "^" },
{ ExpressionType.GreaterThan, ">" },
{ ExpressionType.GreaterThanOrEqual, ">=" },
{ ExpressionType.Increment, "+" },
{ ExpressionType.LeftShift, "<<" },
{ ExpressionType.LeftShiftAssign, "<<" },
{ ExpressionType.LessThan, "<" },
{ ExpressionType.LessThanOrEqual, "<=" },
{ ExpressionType.Modulo, "%" },
{ ExpressionType.ModuloAssign, "%" },
{ ExpressionType.Multiply, "*" },
{ ExpressionType.MultiplyAssign, "*" },
{ ExpressionType.MultiplyAssignChecked, "*" },
{ ExpressionType.MultiplyChecked, "*" },
{ ExpressionType.Not, "!" },
{ ExpressionType.NotEqual, "!" },
{ ExpressionType.OnesComplement, "~" },
{ ExpressionType.Or, "|" },
{ ExpressionType.OrAssign, "|" },
{ ExpressionType.OrElse, "||" },
{ ExpressionType.PostDecrementAssign, "-" },
{ ExpressionType.PostIncrementAssign, "+" },
{ ExpressionType.Power, "^" },
{ ExpressionType.PowerAssign, "^" },
{ ExpressionType.PreDecrementAssign, "-" },
{ ExpressionType.PreIncrementAssign, "+" },
{ ExpressionType.RightShift, ">>" },
{ ExpressionType.RightShiftAssign, ">>" },
{ ExpressionType.Subtract, "-" },
{ ExpressionType.SubtractAssign, "-" },
{ ExpressionType.SubtractAssignChecked, "-" },
{ ExpressionType.SubtractChecked, "-" },
{ ExpressionType.UnaryPlus, "+" }
};
private readonly Lazy<string> _name;
public ExpressionMemberInfo(Expression<Func<T, TProperty>> expression)
{
_name = new Lazy<string>(() => GetName(expression));
}
public override Type DeclaringType
{
get { return typeof(T); }
}
public override MemberTypes MemberType
{
get { return MemberTypes.Custom; }
}
public override string Name
{
get { return _name.Value; }
}
public override Type ReflectedType
{
get { return typeof(T); }
}
public override object[] GetCustomAttributes(Type attributeType, bool inherit)
{
return null;
}
public override object[] GetCustomAttributes(bool inherit)
{
return null;
}
public override bool IsDefined(Type attributeType, bool inherit)
{
return false;
}
private string GetName(Expression<Func<T, TProperty>> expression)
{
//return expression.Body.ToString(); // this returns information we don't want to display to an end user
var members = GetMembers(expression.Body);
var stringBuilder = new StringBuilder();
var first = true;
foreach (var member in members)
{
if (first)
{
stringBuilder.Append(member.Expression.Member.Name);
first = false;
continue;
}
stringBuilder.AppendFormat(" {0} {1}", GetOperatorDescription(member.Operator), member.Expression.Member.Name);
}
return stringBuilder.ToString();
}
private string GetOperatorDescription(ExpressionType? operatorType)
{
return (operatorType != null && _operatorDescriptions.ContainsKey(operatorType.Value))
? _operatorDescriptions[operatorType.Value]
: ",";
}
private IEnumerable<Member> GetMembers(Expression toUnwrap, ExpressionType? type = null)
{
var memberExp = toUnwrap as MemberExpression;
if (memberExp != null) yield return new Member { Expression = memberExp, Operator = type };
var unaryExp = toUnwrap as UnaryExpression;
if (unaryExp != null)
{
foreach (var member in GetMembers(unaryExp.Operand, unaryExp.NodeType))
{
yield return member;
}
}
var binaryExp = toUnwrap as BinaryExpression;
if (binaryExp != null)
{
foreach (var member in GetMembers(binaryExp.Left, type))
{
yield return member;
}
foreach (var member in GetMembers(binaryExp.Right, binaryExp.NodeType))
{
yield return member;
}
}
}
private class Member
{
public MemberExpression Expression { get; set; }
public ExpressionType? Operator { get; set; }
}
}
/// <summary>
/// FluentValidation extension methods that make use of my custom MemberInfo for expressions.
/// </summary>
public static IRuleBuilderOptions<T, TProperty> GreaterThan<T, TProperty>(this IRuleBuilder<T, TProperty> ruleBuilder, Expression<Func<T, TProperty>> expression)
{
return ruleBuilder.SetValidator(new GreaterThanValidator(expression.Compile().CoerceToNonGeneric(), new ExpressionMemberInfo<T, TProperty>(expression)));
}
public static IRuleBuilderOptions<T, TProperty> GreaterThanOrEqual<T, TProperty>(this IRuleBuilder<T, TProperty> ruleBuilder, Expression<Func<T, TProperty>> expression)
{
return ruleBuilder.SetValidator(new GreaterThanOrEqualValidator(expression.Compile().CoerceToNonGeneric(), new ExpressionMemberInfo<T, TProperty>(expression)));
}
public static IRuleBuilderOptions<T, TProperty> LessThan<T, TProperty>(this IRuleBuilder<T, TProperty> ruleBuilder, Expression<Func<T, TProperty>> expression)
{
return ruleBuilder.SetValidator(new LessThanValidator(expression.Compile().CoerceToNonGeneric(), new ExpressionMemberInfo<T, TProperty>(expression)));
}
public static IRuleBuilderOptions<T, TProperty> LessThanOrEqual<T, TProperty>(this IRuleBuilder<T, TProperty> ruleBuilder, Expression<Func<T, TProperty>> expression)
{
return ruleBuilder.SetValidator(new LessThanOrEqualValidator(expression.Compile().CoerceToNonGeneric(), new ExpressionMemberInfo<T, TProperty>(expression)));
}
public static IRuleBuilderOptions<T, TProperty> Equal<T, TProperty>(this IRuleBuilder<T, TProperty> ruleBuilder, Expression<Func<T, TProperty>> expression)
{
return ruleBuilder.SetValidator(new EqualValidator(expression.Compile().CoerceToNonGeneric(), new ExpressionMemberInfo<T, TProperty>(expression)));
}
public static IRuleBuilderOptions<T, TProperty> NotEqual<T, TProperty>(this IRuleBuilder<T, TProperty> ruleBuilder, Expression<Func<T, TProperty>> expression)
{
return ruleBuilder.SetValidator(new NotEqualValidator(expression.Compile().CoerceToNonGeneric(), new ExpressionMemberInfo<T, TProperty>(expression)));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment