Lets say I have a class
public class MyClass
{
public int MyProperty{get;set;}
}
and I want to map property in strogly-typed manner. So instead of typing
MapField("MyProperty", "ColumnName");
I want to have
MapField(x=>x.MyProperty, "ColumnName");
This gives a nice opportunity to refactor, as when renaming MyProperty to something else you will rename it in the mapping as well (though R# can do that for you as it can search literals with property name when renaming a property).
So we need to determine what's the name of property we're passing and also might be interested in it's type.
MapField method should have this signature to work
public void MapField(Expression<Func<MyClass, object>> expression, string columnName)
{
//get field/property name and type from expression
}
Now we have to parse that linq expression. To get required info I've wrote a class with following interface
public interface ILinqExpressionReader<T>
{
string GetFieldOrPropertyNameFromBodyOfExpression(Expression<Func<T, object>> expression);
Type GetFieldTypeFromBodyOfExpression(Expression<Func<T, object>> expression);
}
and here is the implementation:
public class LinqExpressionReader<T> : ILinqExpressionReader<T>
{
public string GetFieldOrPropertyNameFromBodyOfExpression(Expression<Func<T, object>> expression)
{
var memberInfo = GetMemberInfoFrom(expression);
return memberInfo.Name;
}
private static MemberInfo GetMemberInfoFrom(Expression<Func<T, object>> expression)
{
MemberInfo member;
if (expression.Body.GetType() == typeof(UnaryExpression))
{
var unaryExpression = (UnaryExpression)expression.Body;
if (IsMemberExpression(unaryExpression.Operand))
{
member = ((MemberExpression)unaryExpression.Operand).Member;
}
else { throw new ArgumentOutOfRangeException("expression", "Should use the following syntax: x => x.PropertyName (or x => x.FieldName)"); }
}
else if (IsMemberExpression(expression.Body))
{
member = ((MemberExpression)expression.Body).Member;
}
else { throw new ArgumentOutOfRangeException("expression", "Should use the following syntax: x => x.PropertyName"); }
return member;
}
private static bool IsMemberExpression(Expression expression)
{
return expression.GetType() == typeof(MemberExpression);
}
public Type GetFieldTypeFromBodyOfExpression(Expression<Func<T, object>> expression)
{
var memberInfo = GetMemberInfoFrom(expression);
switch (memberInfo.MemberType)
{
case MemberTypes.Property:
return ((PropertyInfo)memberInfo).PropertyType;
case MemberTypes.Field:
return ((FieldInfo)memberInfo).FieldType;
default:
throw new Exception("Cannot get types for anything but Properties and Fields");
}
}
}
Implementation uses reflection to get info that is required. Also works fine with properties or fields of Enum type.
No comments:
Post a Comment