Retrieving Property Name from Lambda Expression

Retrieving Property name from lambda expression

I found another way you can do it was to have the source and property strongly typed and explicitly infer the input for the lambda. Not sure if that is correct terminology but here is the result.

public static RouteValueDictionary GetInfo<T,P>(this HtmlHelper html, Expression<Func<T, P>> action) where T : class
{
var expression = (MemberExpression)action.Body;
string name = expression.Member.Name;

return GetInfo(html, name);
}

And then call it like so.

GetInfo((User u) => u.UserId);

and voila it works.

Get the property name of a property of an anonymous type from an expression

The expression body is a UnaryExpression not because of the anonymous type, but because the property is a value type that needs to be boxed as an object for your Expression<Func<object>>; see this answer.

You can avoid this by changing your method signature to take a generic type parameter:

public static string GetPropertyName<T>(this Expression<Func<T>> property)

Get a property name from a lambda expression *without* an object instance

You can use a property expression the same way as EditorFor. You can do this without an instance.

The one difference is you'll have to specify the type of the expression's parameter to tell the compiler what the object type is. So instead of

EditorFor( x => x.Name );    //Specifies a property but not a type

...your expression would look like this:

EditorFor( (MyType x) => x.Name ); //Specifies property and the type it belongs to

You can accomplish this with a short method like this one:

static PropertyInfo GetPropertyInfo<TIn, TOut>(Expression<Func<TIn, TOut>> expression)
{
var memberExp = expression.Body as MemberExpression;
return memberExp?.Member as PropertyInfo;
}

And then you can do this:

var p1 = GetPropertyInfo((string s) => s.Length);
Console.WriteLine("{0}.{1}", p1.DeclaringType.FullName, p1.Name);

var p2 = GetPropertyInfo((DateTime d) => d.Minute);
Console.WriteLine("{0}.{1}", p2.DeclaringType.FullName, p2.Name);

var p3 = GetPropertyInfo((Stream s) => s.CanSeek);
Console.WriteLine("{0}.{1}", p3.DeclaringType.FullName, p3.Name);

Output:

System.String.Length
System.DateTime.Minute
System.IO.Stream.CanSeek

Notice that we never needed any instances.

Get property name and type using lambda expression

Here's enough of an example of using Expressions to get the name of a property or field to get you started:

public static MemberInfo GetMemberInfo<T, U>(Expression<Func<T, U>> expression)
{
var member = expression.Body as MemberExpression;
if (member != null)
return member.Member;

throw new ArgumentException("Expression is not a member access", "expression");
}

Calling code would look like this:

public class Program
{
public string Name
{
get { return "My Program"; }
}

static void Main()
{
MemberInfo member = ReflectionUtility.GetMemberInfo((Program p) => p.Name);
Console.WriteLine(member.Name);
}
}

A word of caution, though: the simple statment of (Program p) => p.Name actually involves quite a bit of work (and can take measurable amounts of time). Consider caching the result rather than calling the method frequently.

How to get property name from expression

Something like:

private static string GetMemberName(Expression expression)
{
switch(expression.NodeType)
{
case ExpressionType.MemberAccess:
return ((MemberExpression)expression).Member.Name;
case ExpressionType.Convert:
return GetMemberName(((UnaryExpression)expression).Operand);
default:
throw new NotSupportedException(expression.NodeType.ToString());
}
}

with:

public void Exec<T>(Expression<Func<T, object>> expression)
{
string name = GetMemberName(expression.Body);
// ...
}

Get a List of property name with Lambda

I agree with Jon Skeet's comment: nameof is a better way to get arbitrary property names. But assuming that's absolutely not an option, here's one way to do it using expression trees:

public string[] GetPropNames<T1, T2>(Expression<Func<T1, T2>> expression)
{
var newExp = expression.Body as NewExpression;
if (newExp == null)
{
throw new ArgumentException();
}

var props = new List<string>(newExp.Arguments.Count);
foreach (var argExp in newExp.Arguments)
{
var memberExp = argExp as MemberExpression;
if (memberExp == null)
{
throw new ArgumentException();
}
props.Add(memberExp.Member.Name);
}
return props.ToArray();
}

Usage:

GetPropNames((MyObject o) => new { o.MyProp, o.MySecondProp, o.EtcProp })

This is pretty brittle, but it should demonstrate the general principle.

Pass property name by lambda expression for reading attribute values

You can split the work into two functions in order to bypass specifying all generic parameter type for a generic method restriction

public static object[] GetPropertyAttributes<TObject, TProperty>(
this TObject instance,
Expression<Func<TObject, TProperty>> propertySelector)
{
//consider handling exceptions and corner cases
var propertyName = ((PropertyInfo)((MemberExpression)propertySelector.Body).Member).Name;
var property = instance.GetType().GetProperty(propertyName);
return property.GetCustomAttributes(false);
}

public static T GetFirst<T>(this object[] input) where T : Attribute
{
//consider handling exceptions and corner cases
return input.OfType<T>().First();
}

then use it like

foo.GetPropertyAttributes(f => f.Bar)
.GetFirst<StringLengthAttribute>()
.MaximumLength;


Related Topics



Leave a reply



Submit