You can use Lambda Expressions to resolve a compile-time property reference. (code modified from Retrieving Property name from lambda expression)
public PropertyInfo GetPropertyInfo<TProperty>(
Expression<Func<TProperty>> propertyLambda)
{
MemberExpression member = propertyLambda.Body as MemberExpression;
if (member == null)
throw new ArgumentException(string.Format(
"Expression '{0}' refers to a method, not a property.",
propertyLambda.ToString()));
PropertyInfo propInfo = member.Member as PropertyInfo;
if (propInfo == null)
throw new ArgumentException(string.Format(
"Expression '{0}' refers to a field, not a property.",
propertyLambda.ToString()));
return propInfo;
}
You don't need to use it as an extension method (though if you want to adapt it you can, but having a source object instance is not necessary except to write the line)
public class Test
{
public string Prop { get; set; }
}
Test t = new Test();
PropertyInfo propInfo = GetPropertyInfo(() => t.Prop);
Console.WriteLine(propInfo.Name + " -> " + propInfo.PropertyType); //Prop -> System.String
EDIT: If you want to have some nice syntax and have to avoid having an existing reference to an object of the type, you can do something like:
public static class TypedReflection<TSource>
{
public static PropertyInfo GetPropertyInfo<TProperty>(
Expression<Func<TSource, TProperty>> propertyLambda)
{
MemberExpression member = propertyLambda.Body as MemberExpression;
if (member == null)
throw new ArgumentException(string.Format(
"Expression '{0}' refers to a method, not a property.",
propertyLambda.ToString()));
PropertyInfo propInfo = member.Member as PropertyInfo;
if (propInfo == null)
throw new ArgumentException(string.Format(
"Expression '{0}' refers to a field, not a property.",
propertyLambda.ToString()));
return propInfo;
}
}
And call it like:
PropertyInfo propInfo = TypedReflection<Test>.GetPropertyInfo(o => o.Prop);
At this point, it's pretty easy to add additional typed reflection methods (get methods, fields, etc.)
EDIT: It's still sorta two generic types dependent, but it's hidden away through type inference. I prefer the second example; at the very minimum you need to specify the declaring class type (because you want type safety), but you don't need an object instance. It also has the benefit (which I suspect you're after) that if you rename the property, it's propagated to this code obtaining the PropertyInfo
.