Monday, June 15, 2009

Static Reflection

We all get into situation where we need to access class metadata like properties,methods and fields and we use reflection to accomplish it

private class Customer
{
public string LastName { get; set; }
}
[Test]
public void Test()
{
Assert.IsNotNull(typeof(Customer).GetProperty("LastName"));
}


but what will happen if we change the property name of “LastName” to “SurnName” ??



Our test will fail.



But there is a rescue on this one using linq expression trees.



public static class ReflectionExtensions
{
public static MethodInfo GetMethod<TTarget>(this TTarget target, Expression<Action<TTarget>> method)
{
return GetMethodInfo(method);
}

private static MethodInfo GetMethodInfo(Expression method)
{
if (method == null) throw new ArgumentNullException("method");

var lambda = method as LambdaExpression;
if (lambda == null) throw new ArgumentException("Not a lambda expression", "method");
if (lambda.Body.NodeType != ExpressionType.Call) throw new ArgumentException("Not a method call", "method");

return ((MethodCallExpression) lambda.Body).Method;
}

public static PropertyInfo GetProperty<TTarget>(this TTarget target, Expression<Func<TTarget, object>> property)
{
var info = GetMemberInfo(property) as PropertyInfo;
if (info == null) throw new ArgumentException("Member is not a property");

return info;
}


public static FieldInfo GetField<TTarget>(this TTarget target, Expression<Func<TTarget, object>> field)
{
var info = GetMemberInfo(field) as FieldInfo;
if (info == null) throw new ArgumentException("Member is not a field");

return info;
}

private static MemberInfo GetMemberInfo(Expression member)
{
if (member == null) throw new ArgumentNullException("member");

var lambda = member as LambdaExpression;
if (lambda == null) throw new ArgumentException("Not a lambda expression", "member");

MemberExpression memberExpr = null;


if (lambda.Body.NodeType == ExpressionType.Convert)
memberExpr = ((UnaryExpression) lambda.Body).Operand as MemberExpression;
else if (lambda.Body.NodeType == ExpressionType.MemberAccess)
memberExpr = lambda.Body as MemberExpression;

if (memberExpr == null) throw new ArgumentException("Not a member access", "member");

return memberExpr.Member;
}
}


Using the above class one can make the following tests pass

[TestFixture]
public class ReflectionExtensionsFixture
{

public string StringPropertyName { get; set; }

[Test]
public void Property_Info_Can_Be_Found()
{
PropertyInfo property = this.GetProperty(p=>p.StringPropertyName);

Assert.AreEqual("StringPropertyName", property.Name);
}
[Test]
public void Method_Info_Can_Be_Found()
{
MethodInfo methodInfo = this.GetMethod(p => p.PrivateMethod());

Assert.AreEqual("PrivateMethod", methodInfo.Name);
}
private void PrivateMethod()
{

}

public string field;
[Test]
public void FieldInfo_can_be_Found()
{
FieldInfo info = this.GetField(f=>field);
Assert.AreEqual("field", info.Name);
}
}


very cool!!! at my opinion. And you can find endless implementations of it.

Subscribe to XAF feed
Subscribe to community feed

DiggIt!

3 comments:

  1. Is there a way to make this work without instantiating an object? I want to say

    typeof(MyType).GetProperty...

    rather than

    new MyType().GetProperty...

    ReplyDelete
  2. could be!! if u use generics, more like
    new MemberNameReader<MyType>(...)

    ReplyDelete
  3. I'm just learning expression trees and this is a good example of how they can be used.

    ReplyDelete