Specify certain properties of a type - c#

I am trying to initialize objects for tests purposes. After initializing an object, I want to assert that all properties whose underlying type is a value type have a value that is not the default value of the property's type, with certain exceptions. I am not trying to recurse into sub-objects. For this purpose, I have the following:
public static void NoValueTypedPropertyHasDefaultValue<T>(this T t, params string[] exceptions)
where T: class
{
foreach (var property in typeof(T).GetProperties())
{
var propertyType = property.PropertyType;
if (propertyType.IsValueType && !exceptions.Any(x => x == property.Name))
{
var defaultValue = Activator.CreateInstance(propertyType);
object actualValue = property.GetValue(t);
Assert.NotEqual(defaultValue, actualValue);
}
}
}
Provided that everything has a parameterless constructor, it works. I'm not thrilled with the way I'm passing in strings for the exceptions. Is there a better way to do that?

You mentioned in the comments:
I'm not thrilled that the caller could just type in the string, in which case it would not survive a renaming of the property.
Making use of System.Linq.Expressions can give you compile-time safety allowing code such as:
var inst = new MyType { MyInt1 = 1 }; // Set MyInt1 but not MyInt2
inst.NoValueTypedPropertyHasDefaultValue(x => x.MyInt2); // Ignore MyInt2 from validation
The code looks like below (H/T to Retrieving Property name from lambda expression) :
public static class Extensions
{
public static void NoValueTypedPropertyHasDefaultValue<T>(this T t, params Expression<Func<T,object>>[] propertiesToIgnore)
where T : class
{
var propertyNamesToIgnore = propertiesToIgnore.Select(x => GetMemberInfo(x).Member.Name).ToArray();
foreach (var property in typeof(T).GetProperties())
{
var propertyType = property.PropertyType;
if (propertyType.IsValueType && !propertyNamesToIgnore.Contains(property.Name))
{
var defaultValue = Activator.CreateInstance(propertyType);
object actualValue = property.GetValue(t);
Assert.NotEqual(defaultValue, actualValue);
}
}
}
private static MemberExpression GetMemberInfo(Expression method)
{
LambdaExpression lambda = method as LambdaExpression;
if (lambda == null)
throw new ArgumentNullException("method");
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("method");
return memberExpr;
}
}
Live example: https://dotnetfiddle.net/W9Q4gN (Note I have replaced your Assert call with an exception just for testing)
However, if all of that looks a little bit crazy/overkill to you (and to some extent, it really is!!) remember you could have just used nameof with your original scheme. Using my example your code would have become:
var inst = new MyType { MyInt1 = 1 }; // Set MyInt1 but not MyInt2
inst.NoValueTypedPropertyHasDefaultValue(nameof(inst.MyInt2)); // Ignore MyInt2 from validation

Related

C# Simplify property selector in constructor with Generic Type

I'd like to simplify some code, if possible.
Current Constructor (T is within the scope, defined in the outer type)
public Column(string propertyName)
{
PropertyInfo propertyInfo = typeof(T).GetProperty(propertyName);
_ = propertyInfo ?? throw new ArgumentException(message: $"Property {propertyName} does not exist on {typeof(T).Name}");
...
}
I want to know if it is possible to make property a Lambda expression or something to select the property of Generic Type T.
This of course is to make our development easier with fewer mistakes.
Current use
new DataTable<someClass>.Column(nameof(someClass.someProperty))
I would like to do something like:
new DataTable<someClass>.Column(someClass.someProperty) (without declaring a new someClass)
OR
new DataTable<someClass>.Column(t = > t.someProperty)
You can use the below method to extract property name from Expression
public static PropertyInfo GetAccessedMemberInfo<T>(this Expression<T> expression)
{
MemberExpression? memberExpression = null;
if (expression.Body.NodeType == ExpressionType.Convert)
{
memberExpression = ((UnaryExpression)expression.Body).Operand as MemberExpression;
}
else if (expression.Body.NodeType == ExpressionType.MemberAccess)
{
memberExpression = expression.Body as MemberExpression;
}
if (memberExpression == null)
{
throw new ArgumentException("Not a member access", "expression");
}
return memberExpression.Member as PropertyInfo ?? throw new Exception();
}
Then use it like this
public Column(Expression<Func<T, object>> prop)
{
PropertyInfo propertyInfo = prop.GetAccessedMemberInfo();
}
new DataTable<someClass>.Column(t = > t.someProperty)
Previous answer is more complete and support more scenarios, but also more complex.
If you don't need such flexibility, this enforces you to strongly type and also makes sure that the constructor never throws
namespace ConsoleApp1
{
public class Column<T, TProperty>
{
Func<T, TProperty> functionToBeApplied;
// Pass a function, it can never throw
public Column(Func<T, TProperty> functionToBeApplied)
{
this.functionToBeApplied = functionToBeApplied;
}
// Apply the function to the object
public string GetPropertyAsString(T obj)
{
TProperty property = functionToBeApplied(obj);
return property.ToString();
}
}
class Program
{
static void Main(string[] args)
{
var column = new Column<string, int>(x => x.Length);
Console.WriteLine($"Size of string is {column.GetPropertyAsString("this is my object")}");
}
}
}

How to pass objects properties into a generic function

I am trying to create a function that takes in a object property and returns back object property.
How to get the property values into this specific Function, so that this function only takes takes in the object's specific property and not the entire object?
class Program
{
public T MapFrom<T,V>(T SourceObject.property, V DestinationObject.Property)
//Not able to achieve this//
{
// Code to Map Property
}
// Here I want to specifically pass only one property of Object , not the entire one
ProgramClassObject.MapFrom<Details,Person>(Details.FirstName,Person.FName)
}
}
// Class Containing Property
class Details
{
public string FirstName { get; set;}
}
// Class Containing Property
class Person
{
public string FName { get; set;}
}
You can do it manually, or use some library (see comments, someone mentetioned about it).
If still want to implement yourself:
Prepare some useful Expression extensions:
public static B GetProperty<T, B>(this Expression<Func<T, B>> propertySelector, T target) where T : class
{
if (target == null)
{
throw new ArgumentNullException("target");
}
if (propertySelector == null)
{
throw new ArgumentNullException("propertySelector");
}
var memberExpression = propertySelector.Body as MemberExpression;
if (memberExpression == null)
{
throw new NotSupportedException("Only member expression is supported.");
}
var propertyInfo = memberExpression.Member as PropertyInfo;
if (propertyInfo == null)
{
throw new NotSupportedException("You can select property only. Currently, selected member is: " +
memberExpression.Member);
}
return (B)propertyInfo.GetValue(target);
}
public static void SetProperty<T, B>(this Expression<Func<T, B>> propertySelector, T target, B value)
{
SetObjectProperty(target, propertySelector, value);
}
public static void SetObjectProperty<T, B>(T target, Expression<Func<T, B>> propertySelector, object value)
{
if (target == null)
{
throw new ArgumentNullException("target");
}
if (propertySelector == null)
{
throw new ArgumentNullException("propertySelector");
}
var memberExpression = propertySelector.Body as MemberExpression;
if (memberExpression == null)
{
throw new NotSupportedException("Cannot recognize property.");
}
var propertyInfo = memberExpression.Member as PropertyInfo;
if (propertyInfo == null)
{
throw new NotSupportedException("You can select property only. Currently, selected member is: " + memberExpression.Member);
}
propertyInfo.SetValue(target, value);
}
MapFrom implementation:
public static void MapFrom<TObject, TTarget, TProp>(TObject source, TTarget dest,
Expression<Func<TObject, TProp>> sourceSelector, Expression<Func<TTarget, TProp>> targetSelector)
where TObject : class where TTarget : class
{
var sourceValue = sourceSelector.GetProperty(source);
targetSelector.SetProperty(dest, sourceValue);
}
Usage:
programClassObject.MapFrom(details, person, det => det.FirstName, per => per.FName);
It sounds like what you're looking for is an expression. That's how some libraries like Entity Framework effectively "parse" the code that they're passed.
First, you can get the PropertyInfo from an expression through a method such as this. I'm going to explain how to use this below, so bear with me.
public static PropertyInfo GetPropertyInfo<TIn, TOut>(Expression<Func<TIn, TOut>> PropertyExpression)
{
MemberExpression memberExpr;
switch (PropertyExpression.Body.NodeType)
{
case ExpressionType.MemberAccess:
memberExpr = (MemberExpression)PropertyExpression.Body;
break;
case ExpressionType.Convert:
memberExpr = (MemberExpression)((UnaryExpression)PropertyExpression.Body).Operand;
break;
default:
throw new NotSupportedException();
}
var property = (PropertyInfo)memberExpr.Member;
return property;
}
Then, the method will become something like this. I've taken the liberty of ensuring the datatypes to be the same here, although you could change TOut to object if you'd prefer. I did this based on your name of MapFrom, which leads me to believe the properties are meant to "communicate" directly.
public T MapFrom<T, V, TOut>(Expression<Func<T, TOut>> Source, Expression<Func<V, TOut>> Destination)
{
var sourceProperty = GetPropertyInfo<T, TOut>(Source);
var destinationProperty = GetPropertyInfo<V, TOut>(Destination);
// Use those
// They're PropertyInfo instances, so it should be pretty easy to handle them however you would have expected to.
}
Once you've got all that,
var ret = MapFrom<Person, Details, string>(c => c.FName, c => c.FirstName);
The signature there could be cleaned up through the use of a generically typed master class, since you wouldn't have to specify any type arguments, and the string would be inferred. In a real-world situation, that's likely what you'd want to do, particularly since you appear to be, again, mapping values.

Unable to cast object of type 'System.Linq.Expressions.UnaryExpression' to type 'System.Linq.Expressions.MemberExpression'

I created a method in C# to get methodname
public string GetCorrectPropertyName<T>(Expression<Func<T, string>> expression)
{
return ((MemberExpression)expression.Body).Member.Name; // Failure Point
}
and calling it as
string lcl_name = false;
public string Name
{
get { return lcl_name ; }
set
{
lcl_name = value;
OnPropertyChanged(GetCorrectPropertyName<ThisClassName>(x => x.Name));
}
}
This works fine if property is string and for all other types gives this exception:
Unable to cast object of type 'System.Linq.Expressions.UnaryExpression' to type 'System.Linq.Expressions.MemberExpression'.
I changed string to object in method signature, but then it fails again.
I changed calling from x => x.PropertyName to x => Convert.ToString(x.PropertyName) and it still fails
Where am I wrong?
You need a separate line to extract the Member where the input expression is a Unary Expression.
Just converted this from VB.Net, so might be slightly off - let me know if I need to make any minor tweaks:
public string GetCorrectPropertyName<T>(Expression<Func<T, Object>> expression)
{
if (expression.Body is MemberExpression) {
return ((MemberExpression)expression.Body).Member.Name;
}
else {
var op = ((UnaryExpression)expression.Body).Operand;
return ((MemberExpression)op).Member.Name;
}
}
The VB version is:
Public Shared Function GetCorrectPropertyName(Of T) _
(ByVal expression As Expression(Of Func(Of T, Object))) As String
If TypeOf expression.Body Is MemberExpression Then
Return DirectCast(expression.Body, MemberExpression).Member.Name
Else
Dim op = (CType(expression.Body, UnaryExpression).Operand)
Return DirectCast(op, MemberExpression).Member.Name
End If
End Function
Note that the input expression does not return string necessarily - that constrains you to only reading properties that return strings.
This is apparently related to boxing/unboxing. Lambda expressions returning value types that require boxing will be represented as UnaryExpressions whereas those that return reference types will be represented as MemberExpressions.
After asking this question(yes I am OP) i received comments on question from Jon
and I came up with this
public string ResolvePropertyName<TEntity>(Expression<Func<TEntity>> expression)
{
try {
if (expression == null) {
Throw New ArgumentNullException("propertyExpression")
}
object memberExpression = expression.Body as MemberExpression;
if (memberExpression == null) {
Throw New ArgumentException("The expression is not a member access expression.", "propertyExpression")
}
object property = memberExpression.Member as PropertyInfo;
if (property == null) {
Throw New ArgumentException("The member access expression does not access a property.", "propertyExpression")
}
object getMethod = property.GetGetMethod(true);
if (getMethod.IsStatic) {
Throw New ArgumentException("The referenced property is a static property.", "propertyExpression")
}
return memberExpression.Member.Name;
} catch (Exception ex) {
return string.Empty;
}
}
A modern version of the answer above.
private static string GetPropertyName<T>(Expression<Func<T, object>> expression)
=> expression.Body switch
{
MemberExpression expr => expr.Member.Name,
UnaryExpression expr => ((MemberExpression)expr.Operand).Member.Name,
_ => throw new ArgumentException($"Argument {nameof(expression)} is not a property expression.", nameof(expression)),
};
In case you have to handle conditional expressions add this:
else if (expression.Body is ConditionalExpression expr)
{
return ((MemberExpression)((bool)(System.Linq.Expressions.Expression.Lambda(expr.Test).Compile().DynamicInvoke())
? expr.IfTrue
: expr.IfFalse)).Member.Name;
}

Creating an performant open delegate for an property setter or getter

An open delegate is a delegate to an instance method without the target. To call it you supply the target as its first parameter. They are a clever way to optimize code that otherwise would use reflection and have poor performance. For an intro to open delegates see this. The way you would use it in practice is to have expensive reflection code to build these open delegates, but then you would be able to call them very cheaply as a simple Delegate call.
I'm trying to write code that will transform an arbitrary PropertyInfo, into such an delegate for its setter. So far I came up with this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
namespace Test
{
class TestClass
{
static Action<T, object> MakeSetterDelegate<T>(PropertyInfo property)
{
MethodInfo setMethod = property.GetSetMethod();
if (setMethod != null && setMethod.GetParameters().Length == 1) //skips over nasty index properties
{
//To be able to bind to the delegate we have to create a delegate
//type like: Action<T,actualType> rather than Action<T,object>.
//We use reflection to do that
Type setterGenericType = typeof(Action<,>);
Type delegateType = setterGenericType.MakeGenericType(new Type[] { typeof(T), property.PropertyType });
var untypedDelegate = Delegate.CreateDelegate(delegateType, setMethod);
//we wrap the Action<T,actualType> delegate into an Action<T,object>
Action<T, object> setter = (instance, value) =>
{
untypedDelegate.DynamicInvoke(new object[] { instance, value });
};
return setter;
}
else
{
return null;
}
}
int TestProp
{
set
{
System.Diagnostics.Debug.WriteLine("Called set_TestProp");
}
}
static void Test()
{
PropertyInfo property = typeof(TestClass).GetProperty("TestProp");
Action<TestClass, object> setter = MakeSetterDelegate<TestClass>(property);
TestClass instance = new TestClass();
setter(instance, 5);
}
}
}
Similar code would be written for the getter. It works, but the setter delegate uses a DynamicInvoke to convert from an Action<derivedType> to Action<object>, which I suspect is eating a good part of the optimization I'm after. So the questions are:
Is the DynamicInvoke a real concern?
Is there anyway around it?
DynamicInvoke will not make a performant setter. Reflection against a generic inner type is your better option here, as this will allow you to use typed delegates. Another option is DynamicMethod, but then you need to worry about a few IL details.
You might want to look at HyperDescriptor, which wraps up the IL work into a PropertyDescriptor implementation. Another option is the Expression API (if you are using .NET 3.5 or above):
static Action<T, object> MakeSetterDelegate<T>(PropertyInfo property)
{
MethodInfo setMethod = property.GetSetMethod();
if (setMethod != null && setMethod.GetParameters().Length == 1)
{
var target = Expression.Parameter(typeof(T));
var value = Expression.Parameter(typeof(object));
var body = Expression.Call(target, setMethod,
Expression.Convert(value, property.PropertyType));
return Expression.Lambda<Action<T, object>>(body, target, value)
.Compile();
}
else
{
return null;
}
}
Or alternatively with a generic type:
abstract class Setter<T>
{
public abstract void Set(T obj, object value);
}
class Setter<TTarget, TValue> : Setter<TTarget>
{
private readonly Action<TTarget, TValue> del;
public Setter(MethodInfo method)
{
del = (Action<TTarget, TValue>)
Delegate.CreateDelegate(typeof(Action<TTarget, TValue>), method);
}
public override void Set(TTarget obj, object value)
{
del(obj, (TValue)value);
}
}
static Action<T, object> MakeSetterDelegate<T>(PropertyInfo property)
{
MethodInfo setMethod = property.GetSetMethod();
if (setMethod != null && setMethod.GetParameters().Length == 1)
{
Setter<T> untyped = (Setter<T>) Activator.CreateInstance(
typeof(Setter<,>).MakeGenericType(typeof(T),
property.PropertyType), setMethod);
return untyped.Set;
}
else
{
return null;
}
}
I once made this class. Perhaps it helps:
public class GetterSetter<EntityType,propType>
{
private readonly Func<EntityType, propType> getter;
private readonly Action<EntityType, propType> setter;
private readonly string propertyName;
private readonly Expression<Func<EntityType, propType>> propertyNameExpression;
public EntityType Entity { get; set; }
public GetterSetter(EntityType entity, Expression<Func<EntityType, propType>> property_NameExpression)
{
Entity = entity;
propertyName = GetPropertyName(property_NameExpression);
propertyNameExpression = property_NameExpression;
//Create Getter
getter = propertyNameExpression.Compile();
// Create Setter()
MethodInfo method = typeof (EntityType).GetProperty(propertyName).GetSetMethod();
setter = (Action<EntityType, propType>)
Delegate.CreateDelegate(typeof(Action<EntityType, propType>), method);
}
public propType Value
{
get
{
return getter(Entity);
}
set
{
setter(Entity, value);
}
}
protected string GetPropertyName(LambdaExpression _propertyNameExpression)
{
var lambda = _propertyNameExpression as LambdaExpression;
MemberExpression memberExpression;
if (lambda.Body is UnaryExpression)
{
var unaryExpression = lambda.Body as UnaryExpression;
memberExpression = unaryExpression.Operand as MemberExpression;
}
else
{
memberExpression = lambda.Body as MemberExpression;
}
var propertyInfo = memberExpression.Member as PropertyInfo;
return propertyInfo.Name;
}
test:
var gs = new GetterSetter<OnOffElement,bool>(new OnOffElement(), item => item.IsOn);
gs.Value = true;
var result = gs.Value;

Retrieving Property name from lambda expression

Is there a better way to get the Property name when passed in via a lambda expression?
Here is what i currently have.
eg.
GetSortingInfo<User>(u => u.UserId);
It worked by casting it as a memberexpression only when the property was a string. because not all properties are strings i had to use object but then it would return a unaryexpression for those.
public static RouteValueDictionary GetInfo<T>(this HtmlHelper html,
Expression<Func<T, object>> action) where T : class
{
var expression = GetMemberInfo(action);
string name = expression.Member.Name;
return GetInfo(html, name);
}
private static MemberExpression GetMemberInfo(Expression method)
{
LambdaExpression lambda = method as LambdaExpression;
if (lambda == null)
throw new ArgumentNullException("method");
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("method");
return memberExpr;
}
I recently did a very similar thing to make a type safe OnPropertyChanged method.
Here's a method that'll return the PropertyInfo object for the expression. It throws an exception if the expression is not a property.
public PropertyInfo GetPropertyInfo<TSource, TProperty>(
TSource source,
Expression<Func<TSource, TProperty>> propertyLambda)
{
Type type = typeof(TSource);
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()));
if (type != propInfo.ReflectedType &&
!type.IsSubclassOf(propInfo.ReflectedType))
throw new ArgumentException(string.Format(
"Expression '{0}' refers to a property that is not from type {1}.",
propertyLambda.ToString(),
type));
return propInfo;
}
The source parameter is used so the compiler can do type inference on the method call. You can do the following
var propertyInfo = GetPropertyInfo(someUserObject, u => u.UserID);
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.
I was playing around with the same thing and worked this up. It's not fully tested but seems to handle the issue with value types (the unaryexpression issue you ran into)
public static string GetName(Expression<Func<object>> exp)
{
MemberExpression body = exp.Body as MemberExpression;
if (body == null) {
UnaryExpression ubody = (UnaryExpression)exp.Body;
body = ubody.Operand as MemberExpression;
}
return body.Member.Name;
}
public string GetName<TSource, TField>(Expression<Func<TSource, TField>> Field)
{
return (Field.Body as MemberExpression ?? ((UnaryExpression)Field.Body).Operand as MemberExpression).Member.Name;
}
This handles member and unary expressions. The difference being that you will get a UnaryExpression if your expression represents a value type whereas you will get a MemberExpression if your expression represents a reference type. Everything can be cast to an object, but value types must be boxed. This is why the UnaryExpression exists. Reference.
For the sakes of readability (#Jowen), here's an expanded equivalent:
public string GetName<TSource, TField>(Expression<Func<TSource, TField>> Field)
{
if (object.Equals(Field, null))
{
throw new NullReferenceException("Field is required");
}
MemberExpression expr = null;
if (Field.Body is MemberExpression)
{
expr = (MemberExpression)Field.Body;
}
else if (Field.Body is UnaryExpression)
{
expr = (MemberExpression)((UnaryExpression)Field.Body).Operand;
}
else
{
const string Format = "Expression '{0}' not supported.";
string message = string.Format(Format, Field);
throw new ArgumentException(message, "Field");
}
return expr.Member.Name;
}
With C# 7 pattern matching:
public static string GetMemberName<T>(this Expression<T> expression)
{
switch (expression.Body)
{
case MemberExpression m:
return m.Member.Name;
case UnaryExpression u when u.Operand is MemberExpression m:
return m.Member.Name;
default:
throw new NotImplementedException(expression.GetType().ToString());
}
}
Example:
public static RouteValueDictionary GetInfo<T>(this HtmlHelper html,
Expression<Func<T, object>> action) where T : class
{
var name = action.GetMemberName();
return GetInfo(html, name);
}
[Update] C# 8 pattern matching:
public static string GetMemberName<T>(this Expression<T> expression) => expression.Body switch
{
MemberExpression m => m.Member.Name,
UnaryExpression u when u.Operand is MemberExpression m => m.Member.Name,
_ => throw new NotImplementedException(expression.GetType().ToString())
};
now in C# 6 you can simply use nameof like this nameof(User.UserId)
which has many benefits, among them is that this is done at compile time, not runtime.
https://msdn.microsoft.com/en-us/magazine/dn802602.aspx
This is a general implementation to get the string name of fields/properties/indexers/methods/extension methods/delegates of struct/class/interface/delegate/array. I have tested with combinations of static/instance and non-generic/generic variants.
//involves recursion
public static string GetMemberName(this LambdaExpression memberSelector)
{
Func<Expression, string> nameSelector = null; //recursive func
nameSelector = e => //or move the entire thing to a separate recursive method
{
switch (e.NodeType)
{
case ExpressionType.Parameter:
return ((ParameterExpression)e).Name;
case ExpressionType.MemberAccess:
return ((MemberExpression)e).Member.Name;
case ExpressionType.Call:
return ((MethodCallExpression)e).Method.Name;
case ExpressionType.Convert:
case ExpressionType.ConvertChecked:
return nameSelector(((UnaryExpression)e).Operand);
case ExpressionType.Invoke:
return nameSelector(((InvocationExpression)e).Expression);
case ExpressionType.ArrayLength:
return "Length";
default:
throw new Exception("not a proper member selector");
}
};
return nameSelector(memberSelector.Body);
}
This thing can be written in a simple while loop too:
//iteration based
public static string GetMemberName(this LambdaExpression memberSelector)
{
var currentExpression = memberSelector.Body;
while (true)
{
switch (currentExpression.NodeType)
{
case ExpressionType.Parameter:
return ((ParameterExpression)currentExpression).Name;
case ExpressionType.MemberAccess:
return ((MemberExpression)currentExpression).Member.Name;
case ExpressionType.Call:
return ((MethodCallExpression)currentExpression).Method.Name;
case ExpressionType.Convert:
case ExpressionType.ConvertChecked:
currentExpression = ((UnaryExpression)currentExpression).Operand;
break;
case ExpressionType.Invoke:
currentExpression = ((InvocationExpression)currentExpression).Expression;
break;
case ExpressionType.ArrayLength:
return "Length";
default:
throw new Exception("not a proper member selector");
}
}
}
I like the recursive approach, though the second one might be easier to read. One can call it like:
someExpr = x => x.Property.ExtensionMethod()[0]; //or
someExpr = x => Static.Method().Field; //or
someExpr = x => VoidMethod(); //or
someExpr = () => localVariable; //or
someExpr = x => x; //or
someExpr = x => (Type)x; //or
someExpr = () => Array[0].Delegate(null); //etc
string name = someExpr.GetMemberName();
to print the last member.
Note:
In case of chained expressions like A.B.C, "C" is returned.
This doesn't work with consts, array indexers or enums (impossible to cover all cases).
There's an edge case when it comes to Array.Length. While 'Length' is exposed as a property, you can't use it in any of the previously proposed solutions.
using Contract = System.Diagnostics.Contracts.Contract;
using Exprs = System.Linq.Expressions;
static string PropertyNameFromMemberExpr(Exprs.MemberExpression expr)
{
return expr.Member.Name;
}
static string PropertyNameFromUnaryExpr(Exprs.UnaryExpression expr)
{
if (expr.NodeType == Exprs.ExpressionType.ArrayLength)
return "Length";
var mem_expr = expr.Operand as Exprs.MemberExpression;
return PropertyNameFromMemberExpr(mem_expr);
}
static string PropertyNameFromLambdaExpr(Exprs.LambdaExpression expr)
{
if (expr.Body is Exprs.MemberExpression) return PropertyNameFromMemberExpr(expr.Body as Exprs.MemberExpression);
else if (expr.Body is Exprs.UnaryExpression) return PropertyNameFromUnaryExpr(expr.Body as Exprs.UnaryExpression);
throw new NotSupportedException();
}
public static string PropertyNameFromExpr<TProp>(Exprs.Expression<Func<TProp>> expr)
{
Contract.Requires<ArgumentNullException>(expr != null);
Contract.Requires<ArgumentException>(expr.Body is Exprs.MemberExpression || expr.Body is Exprs.UnaryExpression);
return PropertyNameFromLambdaExpr(expr);
}
public static string PropertyNameFromExpr<T, TProp>(Exprs.Expression<Func<T, TProp>> expr)
{
Contract.Requires<ArgumentNullException>(expr != null);
Contract.Requires<ArgumentException>(expr.Body is Exprs.MemberExpression || expr.Body is Exprs.UnaryExpression);
return PropertyNameFromLambdaExpr(expr);
}
Now example usage:
int[] someArray = new int[1];
Console.WriteLine(PropertyNameFromExpr( () => someArray.Length ));
If PropertyNameFromUnaryExpr didn't check for ArrayLength, "someArray" would be printed to the console (compiler seems to generate direct access to the backing Length field, as an optimization, even in Debug, thus the special case).
Here's an update to method proposed by Cameron. The first parameter is not required.
public PropertyInfo GetPropertyInfo<TSource, TProperty>(
Expression<Func<TSource, TProperty>> propertyLambda)
{
Type type = typeof(TSource);
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()));
if (type != propInfo.ReflectedType &&
!type.IsSubclassOf(propInfo.ReflectedType))
throw new ArgumentException(string.Format(
"Expresion '{0}' refers to a property that is not from type {1}.",
propertyLambda.ToString(),
type));
return propInfo;
}
You can do the following:
var propertyInfo = GetPropertyInfo<SomeType>(u => u.UserID);
var propertyInfo = GetPropertyInfo((SomeType u) => u.UserID);
Extension methods:
public static PropertyInfo GetPropertyInfo<TSource, TProperty>(this TSource source,
Expression<Func<TSource, TProperty>> propertyLambda) where TSource : class
{
return GetPropertyInfo(propertyLambda);
}
public static string NameOfProperty<TSource, TProperty>(this TSource source,
Expression<Func<TSource, TProperty>> propertyLambda) where TSource : class
{
PropertyInfo prodInfo = GetPropertyInfo(propertyLambda);
return prodInfo.Name;
}
You can:
SomeType someInstance = null;
string propName = someInstance.NameOfProperty(i => i.Length);
PropertyInfo propInfo = someInstance.GetPropertyInfo(i => i.Length);
I've found that some of the suggested answers which drill down into the MemberExpression/UnaryExpression don't capture nested/subproperties.
ex) o => o.Thing1.Thing2 returns Thing1 rather than Thing1.Thing2.
This distinction is important if you're trying to work with EntityFramework DbSet.Include(...).
I've found that just parsing the Expression.ToString() seems to work fine, and comparatively quickly. I compared it against the UnaryExpression version, and even getting ToString off of the Member/UnaryExpression to see if that was faster, but the difference was negligible. Please correct me if this is a terrible idea.
The Extension Method
/// <summary>
/// Given an expression, extract the listed property name; similar to reflection but with familiar LINQ+lambdas. Technique #via https://stackoverflow.com/a/16647343/1037948
/// </summary>
/// <remarks>Cheats and uses the tostring output -- Should consult performance differences</remarks>
/// <typeparam name="TModel">the model type to extract property names</typeparam>
/// <typeparam name="TValue">the value type of the expected property</typeparam>
/// <param name="propertySelector">expression that just selects a model property to be turned into a string</param>
/// <param name="delimiter">Expression toString delimiter to split from lambda param</param>
/// <param name="endTrim">Sometimes the Expression toString contains a method call, something like "Convert(x)", so we need to strip the closing part from the end</param>
/// <returns>indicated property name</returns>
public static string GetPropertyName<TModel, TValue>(this Expression<Func<TModel, TValue>> propertySelector, char delimiter = '.', char endTrim = ')') {
var asString = propertySelector.ToString(); // gives you: "o => o.Whatever"
var firstDelim = asString.IndexOf(delimiter); // make sure there is a beginning property indicator; the "." in "o.Whatever" -- this may not be necessary?
return firstDelim < 0
? asString
: asString.Substring(firstDelim+1).TrimEnd(endTrim);
}//-- fn GetPropertyNameExtended
(Checking for the delimiter might even be overkill)
Demo (LinqPad)
Demonstration + Comparison code -- https://gist.github.com/zaus/6992590
I"m using an extension method for pre C# 6 projects and the nameof() for those targeting C# 6.
public static class MiscExtentions
{
public static string NameOf<TModel, TProperty>(this object #object, Expression<Func<TModel, TProperty>> propertyExpression)
{
var expression = propertyExpression.Body as MemberExpression;
if (expression == null)
{
throw new ArgumentException("Expression is not a property.");
}
return expression.Member.Name;
}
}
And i call it like:
public class MyClass
{
public int Property1 { get; set; }
public string Property2 { get; set; }
public int[] Property3 { get; set; }
public Subclass Property4 { get; set; }
public Subclass[] Property5 { get; set; }
}
public class Subclass
{
public int PropertyA { get; set; }
public string PropertyB { get; set; }
}
// result is Property1
this.NameOf((MyClass o) => o.Property1);
// result is Property2
this.NameOf((MyClass o) => o.Property2);
// result is Property3
this.NameOf((MyClass o) => o.Property3);
// result is Property4
this.NameOf((MyClass o) => o.Property4);
// result is PropertyB
this.NameOf((MyClass o) => o.Property4.PropertyB);
// result is Property5
this.NameOf((MyClass o) => o.Property5);
It works fine with both fields and properties.
Well, there's no need to call .Name.ToString(), but broadly that is about it, yes. The only consideration you might need is whether x.Foo.Bar should return "Foo", "Bar", or an exception - i.e. do you need to iterate at all.
(re comment) for more on flexible sorting, see here.
This might be optimal
public static string GetPropertyName<TResult>(Expression<Func<TResult>> expr)
{
var memberAccess = expr.Body as MemberExpression;
var propertyInfo = memberAccess?.Member as PropertyInfo;
var propertyName = propertyInfo?.Name;
return propertyName;
}
I leave this function if you want to get multiples fields:
/// <summary>
/// Get properties separated by , (Ex: to invoke 'd => new { d.FirstName, d.LastName }')
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="exp"></param>
/// <returns></returns>
public static string GetFields<T>(Expression<Func<T, object>> exp)
{
MemberExpression body = exp.Body as MemberExpression;
var fields = new List<string>();
if (body == null)
{
NewExpression ubody = exp.Body as NewExpression;
if (ubody != null)
foreach (var arg in ubody.Arguments)
{
fields.Add((arg as MemberExpression).Member.Name);
}
}
return string.Join(",", fields);
}
I created an extension method on ObjectStateEntry to be able to flag properties (of Entity Framework POCO classes) as modified in a type safe manner, since the default method only accepts a string. Here's my way of getting the name from the property:
public static void SetModifiedProperty<T>(this System.Data.Objects.ObjectStateEntry state, Expression<Func<T>> action)
{
var body = (MemberExpression)action.Body;
string propertyName = body.Member.Name;
state.SetModifiedProperty(propertyName);
}
I have done the INotifyPropertyChanged implementation similar to the method below. Here the properties are stored in a dictionary in the base class shown below. It is of course not always desirable to use inheritance, but for view models I think it is acceptable and gives very clean property references in the view model classes.
public class PhotoDetailsViewModel
: PropertyChangedNotifierBase<PhotoDetailsViewModel>
{
public bool IsLoading
{
get { return GetValue(x => x.IsLoading); }
set { SetPropertyValue(x => x.IsLoading, value); }
}
public string PendingOperation
{
get { return GetValue(x => x.PendingOperation); }
set { SetPropertyValue(x => x.PendingOperation, value); }
}
public PhotoViewModel Photo
{
get { return GetValue(x => x.Photo); }
set { SetPropertyValue(x => x.Photo, value); }
}
}
The somewhat more complex base class is shown below. It handles the translation from lambda expression to property name. Note that the properties are really pseudo properties since only the names are used. But it will appear transparent to the view model and references to the properties on the view model.
public class PropertyChangedNotifierBase<T> : INotifyPropertyChanged
{
readonly Dictionary<string, object> _properties = new Dictionary<string, object>();
protected U GetValue<U>(Expression<Func<T, U>> property)
{
var propertyName = GetPropertyName(property);
return GetValue<U>(propertyName);
}
private U GetValue<U>(string propertyName)
{
object value;
if (!_properties.TryGetValue(propertyName, out value))
{
return default(U);
}
return (U)value;
}
protected void SetPropertyValue<U>(Expression<Func<T, U>> property, U value)
{
var propertyName = GetPropertyName(property);
var oldValue = GetValue<U>(propertyName);
if (Object.ReferenceEquals(oldValue, value))
{
return;
}
_properties[propertyName] = value;
RaisePropertyChangedEvent(propertyName);
}
protected void RaisePropertyChangedEvent<U>(Expression<Func<T, U>> property)
{
var name = GetPropertyName(property);
RaisePropertyChangedEvent(name);
}
protected void RaisePropertyChangedEvent(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private static string GetPropertyName<U>(Expression<Func<T, U>> property)
{
if (property == null)
{
throw new NullReferenceException("property");
}
var lambda = property as LambdaExpression;
var memberAssignment = (MemberExpression) lambda.Body;
return memberAssignment.Member.Name;
}
public event PropertyChangedEventHandler PropertyChanged;
}
This is another answer:
public static string GetPropertyName<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper,
Expression<Func<TModel, TProperty>> expression)
{
var metaData = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
return metaData.PropertyName;
}
Here is another way to get the PropertyInfo based off this answer. It eliminates the need for an object instance.
/// <summary>
/// Get metadata of property referenced by expression. Type constrained.
/// </summary>
public static PropertyInfo GetPropertyInfo<TSource, TProperty>(Expression<Func<TSource, TProperty>> propertyLambda)
{
return GetPropertyInfo((LambdaExpression) propertyLambda);
}
/// <summary>
/// Get metadata of property referenced by expression.
/// </summary>
public static PropertyInfo GetPropertyInfo(LambdaExpression propertyLambda)
{
// https://stackoverflow.com/questions/671968/retrieving-property-name-from-lambda-expression
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()));
if(propertyLambda.Parameters.Count() == 0)
throw new ArgumentException(String.Format(
"Expression '{0}' does not have any parameters. A property expression needs to have at least 1 parameter.",
propertyLambda.ToString()));
var type = propertyLambda.Parameters[0].Type;
if (type != propInfo.ReflectedType &&
!type.IsSubclassOf(propInfo.ReflectedType))
throw new ArgumentException(String.Format(
"Expression '{0}' refers to a property that is not from type {1}.",
propertyLambda.ToString(),
type));
return propInfo;
}
It can be called like so:
var propertyInfo = GetPropertyInfo((User u) => u.UserID);
GetPropetyAccess() is available if you can refer efcore.
using Microsoft.EntityFrameworkCore.Infrastructure;
var propertyInfo = lambda.GetPropetyAccess(); //PropertyInfo
var propertyName = propertyInfo.Name;
I've updated #Cameron's answer to include some safety checks against Convert typed lambda expressions:
PropertyInfo GetPropertyName<TSource, TProperty>(
Expression<Func<TSource, TProperty>> propertyLambda)
{
var body = propertyLambda.Body;
if (!(body is MemberExpression member)
&& !(body is UnaryExpression unary
&& (member = unary.Operand as MemberExpression) != null))
throw new ArgumentException($"Expression '{propertyLambda}' " +
"does not refer to a property.");
if (!(member.Member is PropertyInfo propInfo))
throw new ArgumentException($"Expression '{propertyLambda}' " +
"refers to a field, not a property.");
var type = typeof(TSource);
if (!propInfo.DeclaringType.GetTypeInfo().IsAssignableFrom(type.GetTypeInfo()))
throw new ArgumentException($"Expresion '{propertyLambda}' " +
"refers to a property that is not from type '{type}'.");
return propInfo;
}
Starting with .NET 4.0 you can use ExpressionVisitor to find properties:
class ExprVisitor : ExpressionVisitor {
public bool IsFound { get; private set; }
public string MemberName { get; private set; }
public Type MemberType { get; private set; }
protected override Expression VisitMember(MemberExpression node) {
if (!IsFound && node.Member.MemberType == MemberTypes.Property) {
IsFound = true;
MemberName = node.Member.Name;
MemberType = node.Type;
}
return base.VisitMember(node);
}
}
Here is how you use this visitor:
var visitor = new ExprVisitor();
visitor.Visit(expr);
if (visitor.IsFound) {
Console.WriteLine("First property in the expression tree: Name={0}, Type={1}", visitor.MemberName, visitor.MemberType.FullName);
} else {
Console.WriteLine("No properties found.");
}
static void Main(string[] args)
{
var prop = GetPropertyInfo<MyDto>(_ => _.MyProperty);
MyDto dto = new MyDto();
dto.MyProperty = 666;
var value = prop.GetValue(dto);
// value == 666
}
class MyDto
{
public int MyProperty { get; set; }
}
public static PropertyInfo GetPropertyInfo<TSource>(Expression<Func<TSource, object>> propertyLambda)
{
Type type = typeof(TSource);
var member = propertyLambda.Body as MemberExpression;
if (member == null)
{
var unary = propertyLambda.Body as UnaryExpression;
if (unary != null)
{
member = unary.Operand as MemberExpression;
}
}
if (member == null)
{
throw new ArgumentException(string.Format("Expression '{0}' refers to a method, not a property.",
propertyLambda.ToString()));
}
var propInfo = member.Member as PropertyInfo;
if (propInfo == null)
{
throw new ArgumentException(string.Format("Expression '{0}' refers to a field, not a property.",
propertyLambda.ToString()));
}
if (type != propInfo.ReflectedType && !type.IsSubclassOf(propInfo.ReflectedType))
{
throw new ArgumentException(string.Format("Expression '{0}' refers to a property that is not from type {1}.",
propertyLambda.ToString(), type));
}
return propInfo;
}
Assuming (TModel as class)
Expression<Func<TModel, TValue>> expression
retrieve the property's name with
expression.GetPropertyInfo().Name;
The extension function:
public static PropertyInfo GetPropertyInfo<TType, TReturn>(this Expression<Func<TType, TReturn>> property)
{
LambdaExpression lambda = property;
var memberExpression = lambda.Body is UnaryExpression expression
? (MemberExpression)expression.Operand
: (MemberExpression)lambda.Body;
return (PropertyInfo)memberExpression.Member;
}

Categories