How this code works for handling INotifyPropertyChanged - c#

I see below code in this link : An elegant way to implement INotifyPropertyChanged
I'm new to Expression Tree.can any one please explane how this code work simply?
thanks
private string _name;
public string Name
{
get { return _name; }
set { PropertyChanged.ChangeAndNotify(ref _name, value, () => Name); }
}
public static bool ChangeAndNotify<T>(this PropertyChangedEventHandler handler,ref T field, T value, Expression<Func<T>> memberExpression)
{
if (memberExpression == null)
{
throw new ArgumentNullException("memberExpression");
}
var body = memberExpression.Body as MemberExpression;
if (body == null)
{
throw new ArgumentException("Lambda must return a property.");
}
if (EqualityComparer<T>.Default.Equals(field, value))
{
return false;
}
var vmExpression = body.Expression as ConstantExpression;
if (vmExpression != null)
{
LambdaExpression lambda = Expression.Lambda(vmExpression);
Delegate vmFunc = lambda.Compile();
object sender = vmFunc.DynamicInvoke();
if (handler != null)
{
handler(sender, new PropertyChangedEventArgs(body.Member.Name));
}
}
field = value;
return true;
}

An expression tree is an object-oriented representation of an expression at runtime. The C# compiler can automatically write a limited subset of expressions as Expression<> instances, via a lambda - i.e.
Func<string> anonMethod = () => "abc"; // this is a delegate
Expression<Func<string>> expression = () => "abc"; // this is an expression
The above will have a ConstantExpression; your example will have a ConstantExpression that captures this and a MemberExpression that wraps that constant (this) and the member (.Name). Then at runtime, it locates the MemberExpression, which has a MemberInfo, which has a Name. It could even have a ConstantExpression to a capture class, a MemberExpression to this (as a field on the capture-class), and then a MemberExpression to .Name.
The difference is subtle, but an expression can be pulled apart and inspected at runtime - which is critical for LINQ. However: while the compiler can write these, they are not free to inspect; they have cost too.
IMO, perhaps stick with:
public string Name
{
get { return _name; }
set { SomeSimpleNotifyMethod(ref _name, value, this, "Name"; }
}
this is simpler and faster (obviously, changing the method to take a string that it passes to the event).

Here's an extension method that is able to determine sender and property name just by inspecting lambda expression tree and without any major performance impact:
public static class PropertyChangedExtensions
{
public static void Raise(this PropertyChangedEventHandler handler, Expression<Func<object>> property)
{
if (handler == null)
return;
var boxingExpr = property.Body as UnaryExpression;
var memberExpr = (MemberExpression)(boxingExpr == null ?
property.Body : boxingExpr.Operand);
var propertyName = memberExpr.Member.Name;
var sender = ((ConstantExpression)memberExpr.Expression).Value;
handler.Invoke(sender, new PropertyChangedEventArgs(propertyName));
}
}
and usage is the same as you have right now:
public string Name
{
get { return name; }
set
{
name = value;
PropertyChanged.Raise(() => Name);
}
}

Related

Reading lambda expression [duplicate]

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;
}

C# How to get nameof a sentence as String [duplicate]

I'm developing a API that uses lambda expressions to specify properties. I'm using this famous piece of code similar to this one (this is simplified and incomplete, just to make clear what I'm talking about):
public void Foo<T, P>(Expression<Func<T, P>> action)
{
var expression = (MemberExpression)action.Body;
string propertyName = expression.Member.Name;
// ...
}
To be called like this:
Foo((String x) => x.Length);
Now I would like to specify a property path by chaining property names, like this:
Foo((MyClass x) => x.Name.Length);
Foo should be able to split the path into its property names ("Name" and "Length"). Is there a way to do this with reasonable effort?
There is a somehow similar looking question, but I think they are trying to combine lambda expressions there.
Another question also is dealing with nested property names, but I don't really understand what they are talking about.
Something like this?
public void Foo<T, P>(Expression<Func<T, P>> expr)
{
MemberExpression me;
switch (expr.Body.NodeType)
{
case ExpressionType.Convert:
case ExpressionType.ConvertChecked:
var ue = expr.Body as UnaryExpression;
me = ((ue != null) ? ue.Operand : null) as MemberExpression;
break;
default:
me = expr.Body as MemberExpression;
break;
}
while (me != null)
{
string propertyName = me.Member.Name;
Type propertyType = me.Type;
Console.WriteLine(propertyName + ": " + propertyType);
me = me.Expression as MemberExpression;
}
}
I played a little with ExpressionVisitor:
public static class PropertyPath<TSource>
{
public static IReadOnlyList<MemberInfo> Get<TResult>(Expression<Func<TSource, TResult>> expression)
{
var visitor = new PropertyVisitor();
visitor.Visit(expression.Body);
visitor.Path.Reverse();
return visitor.Path;
}
private class PropertyVisitor : ExpressionVisitor
{
internal readonly List<MemberInfo> Path = new List<MemberInfo>();
protected override Expression VisitMember(MemberExpression node)
{
if (!(node.Member is PropertyInfo))
{
throw new ArgumentException("The path can only contain properties", nameof(node));
}
this.Path.Add(node.Member);
return base.VisitMember(node);
}
}
}
Usage:
var path = string.Join(".", PropertyPath<string>.Get(x => x.Length).Select(p => p.Name));
Old question, I know... but if it's only the names you need, an even simpler way to do it is:
expr.ToString().Split('.').Skip(1)
EDIT:
public class A
{
public B Property { get; set; }
}
public class B
{
public C field;
}
[Fact]
public void FactMethodName()
{
var exp = (Expression<Func<A, object>>) (x => x.Property.field);
foreach (var part in exp.ToString().Split('.').Skip(1))
Console.WriteLine(part);
// Output:
// Property
// field
}
I have a shared .NET standard DTO between client and server and expressions are a great way to create query strings that can be rebuilt and executed Api side.
A perfect way to create Type safe queries over the wire.
I digress, I needed a property path also
x => x.Siblings.Age
To produce a string like
"Siblings.Age"
I went with this
public static string GetMemberPath(MemberExpression me)
{
var parts = new List<string>();
while (me != null)
{
parts.Add(me.Member.Name);
me = me.Expression as MemberExpression;
}
parts.Reverse();
return string.Join(".", parts);
}
public static string GetPath<T, TProperty>(this Expression<Func<T, TProperty>> exp)
{
return string.Join(".", GetItemsInPath(exp).Reverse());
}
private static IEnumerable<string> GetItemsInPath<T, TProperty>(Expression<Func<T, TProperty>> exp)
{
if (exp == null)
{
yield break;
}
var memberExp = FindMemberExpression(exp.Body);
while (memberExp != null)
{
yield return memberExp.Member.Name;
memberExp = FindMemberExpression(memberExp.Expression);
}
}
I refactored these answers to use recursion, so no need for order reversal. I only need the property tree, so left out all but MemberExpressions. Should be simple to add functionality if need be.
public IEnumerable<string> PropertyPath<TModel, TValue>(
Expression<Func<TModel, TValue>> expression)
{
if (expression.Body is MemberExpression memberExpression)
return PropertyPathRecurse(memberExpression);
return Enumerable.Empty<string>();
}
private IEnumerable<string> PropertyPathRecurse(MemberExpression? expression)
{
if (expression is null)
return Enumerable.Empty<string>();
return PropertyPathRecurse(expression.Expression as MemberExpression)
.Append(expression.Member.Name);
}

How to rise PropertyChanged event without passing property name as a string?

In wpf we often use following pattern for bindable properties:
private Foo _bar = new Foo();
public Foo Bar
{
get { return _bar; }
set
{
_bar = value;
OnPropertyChanged();
}
}
public void OnPropertyChanged([CallerMemberName] string property = "")
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
CallerMemberNameAttribute does nice magic, generating for us "Bar" parameter from setter name.
However, often there are properties without setter or dependent properties:
private Foo _bar;
public Foo Bar
{
get { return _bar; }
set
{
_bar = value;
OnPropertyChanged();
}
}
public bool IsBarNull
{
get { return _bar == null; }
}
In given example, when Bar is changed then IsBarNull needs event too. We can add OnPropertyChanged("IsBarNull"); into Bar setters, but ... using string for properties is:
ugly;
hard to refactor (VS's "Rename" will not rename property name in string);
can be a source of all kind of mistakes.
WPF exists for so long. Is there no magical solution yet (similar to CallerMemberNameAttribute)?
Use C# 6 and the nameof feature:
OnPropertyChange(nameof(IsBarNull));
That generates equivalent code to:
OnPropertyChange("IsBarNull");
... but without the fragility.
If you're stuck on earlier versions of C#, you can use expression trees for this, but I regard that as a bit of a hack and a potential performance issue (as the tree is recreated on each call). nameof doesn't require any library support, just a new compiler - so if you upgrade to VS 2015 (or later, dear readers from the future...) you should be fine.
if C# 6 is not at hand, here's some method i'm using quite often using Expressions:
public static class ExpressionExtensions
{
public static string GetMemberName<T>(this Expression<Func<T, object>> expression)
{
return GetMemberName(expression.Body);
}
public static string GetMemberName (this Expression propertyExpression)
{
var lambda = propertyExpression as LambdaExpression;
MemberExpression memberExpression = null;
if (propertyExpression is UnaryExpression)
{
var unaryExpression = propertyExpression as UnaryExpression;
memberExpression = unaryExpression.Operand as MemberExpression;
}
else if (lambda != null && lambda.Body is UnaryExpression)
{
var unaryExpression = lambda.Body as UnaryExpression;
memberExpression = unaryExpression.Operand as MemberExpression;
}
else if (lambda != null)
{
memberExpression = lambda.Body as MemberExpression;
}
else
{
var expression = propertyExpression as MemberExpression;
if (expression != null)
memberExpression = expression;
}
if (memberExpression == null) return null;
var propertyInfo = memberExpression.Member;
return propertyInfo.Name;
}
}
usage:
var propertyName = ExpressionExtensions.GetMemberName<DateTime>(item => item.Day);
DevExpress offers in it's BindableBase class a method SetProperty which reflects on the property you like to set:
private Foo _bar;
public Foo Bar
{
get { return _bar; }
set
{
SetProperty(ref _bar, value, () => Bar);
}
}
It automatically looks for the correct property to update and only sends property changed events if necessary

How to get rid of repetitive properties in WPF MVVM viewmodels

I am setting up a WPF application with a ViewModel that has lots of properties. These are all very repetitive and I am wondering if there is a way to get rid of this. This is what one property looks like, and I have about 8-10 of them.
public string Name
{
get
{
return this.name;
}
set
{
if (this.name != value)
{
this.name = value;
this.RaisePropertyChanged("Name");
}
}
}
My suggestion, if your requirements are straightforward, would be to go third party. This is a solved problem, thanks to some ingenious people...
The most bare-bones way you can write your code is to remove the INotifyPropertyChanged implementation entirely, and write your properties in the minimal way like this:
public string Name { get; set; }
Then add Fody.PropertyChanged to your project (it's on NuGet) and mark your class with the [ImplementPropertyChanged] attribute.
Fody will do some clever IL magic during compilation that will implement the interface and all of the boilerplate code magically - meaning your written code is as simple as can be, and your end result is exactly what you want.
Note that if you rely on the INotifyPropertyChanged interface elsewhere in your code (that is, if you manually attach to the event in code or similar), you may want to use Fody differently because the IDE won't realise you've got the interface implemented. Fortunately, Fody will also auto-implement in other scenarios too (e.g.: implement INotifyPropertyChanged in a class and Fody will, by default also implement event raising in your properties).
The mentioned thread contains indeed the answer but you need to do some digging. I will show the two best answers I found in there.
The first solution is to implement a ViewModelBase class that encapsulates the set method into a template method and uses lamda expressions to retrieve the Property name so refactoring does not break the property name string.
public class ViewModelBase: INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
protected virtual void OnPropertyChanged<T>(Expression<Func<T>> selectorExpression)
{
if (selectorExpression == null)
throw new ArgumentNullException("selectorExpression");
var body = selectorExpression.Body as MemberExpression;
if (body == null)
throw new ArgumentException("The body must be a member expression");
OnPropertyChanged(body.Member.Name);
}
protected bool SetField<T>(ref T field, T value, Expression<Func<T>> selectorExpression)
{
if (EqualityComparer<T>.Default.Equals(field, value)) return false;
field = value;
OnPropertyChanged(selectorExpression);
return true;
}
}
Usage:
class ViewModel : DataBase
{
private String _prop1;
public String Prop1
{
get { return _prop1; }
set
{
SetField(ref _prop1, value, () => Prop1);
}
}
}
The second solution uses a Dictionary to store the properties in the base class. This way we do not need to pass in the old value as it is kept in the base class and we do not need to create member fields to hold the values for the properties. I like this solution the best:
public abstract class ViewModelBase : INotifyPropertyChanged
{
private readonly Dictionary<string, object> _propertyValueStorage;
#region Constructor
protected ViewModelBase()
{
this._propertyValueStorage = new Dictionary<string, object>();
}
#endregion
protected void SetValue<T>(Expression<Func<T>> property, T value)
{
var lambdaExpression = property as LambdaExpression;
if (lambdaExpression == null)
{
throw new ArgumentException("Invalid lambda expression", "Lambda expression return value can't be null");
}
var propertyName = this.getPropertyName(lambdaExpression);
var storedValue = this.getValue<T>(propertyName);
if (object.Equals(storedValue, value)) return;
this._propertyValueStorage[propertyName] = value;
this.OnPropertyChanged(propertyName);
}
protected T GetValue<T>(Expression<Func<T>> property)
{
var lambdaExpression = property as LambdaExpression;
if (lambdaExpression == null)
{
throw new ArgumentException("Invalid lambda expression", "Lambda expression return value can't be null");
}
var propertyName = this.getPropertyName(lambdaExpression);
return getValue<T>(propertyName);
}
private T getValue<T>(string propertyName)
{
object value;
if (_propertyValueStorage.TryGetValue(propertyName, out value))
{
return (T)value;
}
return default(T);
}
private string getPropertyName(LambdaExpression lambdaExpression)
{
MemberExpression memberExpression;
if (lambdaExpression.Body is UnaryExpression)
{
var unaryExpression = lambdaExpression.Body as UnaryExpression;
memberExpression = unaryExpression.Operand as MemberExpression;
}
else
{
memberExpression = lambdaExpression.Body as MemberExpression;
}
return memberExpression.Member.Name;
}
#region < INotifyPropertyChanged > Members
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
Usage would be:
public class ViewModel : ViewModelBase
{
public String Prop1
{
get { return GetValue(() => Prop1); }
set { SetValue(() => Prop1, value); }
}
public bool Bool1
{
get { return GetValue(() => Bool1); }
set { SetValue(() => Bool1, value); }
}
Solution 1 is based on https://stackoverflow.com/a/1316566/2259878 and https://stackoverflow.com/a/1316566/2259878
Solution 2 is based on http://dotnet-forum.de/blogs/thearchitect/archive/2012/11/01/die-optimale-implementierung-des-inotifypropertychanged-interfaces.aspx
It depends on the requirement, if all the properties are used for same purpose means like name1, name2, name3.....name10, like listing names of 10 people, then put in a another class and bind a collection of the class type to Items-control in your xaml. or simply bind a ObservableCollection of string
But if each of properties has its own purpose then it can not avoid, because Properties are nothing but variables to hold different values. Each property will have it's own intention and operation on each of them will vary in the view model, depending on logic
My solution is near to uncletall's but with some changes for usage
private static readonly Properties<MainWindowViewModel> _properties = new Properties<MainWindowViewModel>();
public static Property TextProperty = _properties.Create(_ => _.Text);
private string _text;
public string Text
{
get { return _text; }
set { SetProperty(ref _text, value, TextProperty); }
}
XAML:
<Label Grid.Row="1" Content="{Model:PropertyBinding {x:Static Model:MainWindowViewModel.TextProperty}}" Width="200"/>
Benefit of this sample is compile-time check for changes.
Full sample link

C#: Getting Names of properties in a chain from lambda expression

I'm developing a API that uses lambda expressions to specify properties. I'm using this famous piece of code similar to this one (this is simplified and incomplete, just to make clear what I'm talking about):
public void Foo<T, P>(Expression<Func<T, P>> action)
{
var expression = (MemberExpression)action.Body;
string propertyName = expression.Member.Name;
// ...
}
To be called like this:
Foo((String x) => x.Length);
Now I would like to specify a property path by chaining property names, like this:
Foo((MyClass x) => x.Name.Length);
Foo should be able to split the path into its property names ("Name" and "Length"). Is there a way to do this with reasonable effort?
There is a somehow similar looking question, but I think they are trying to combine lambda expressions there.
Another question also is dealing with nested property names, but I don't really understand what they are talking about.
Something like this?
public void Foo<T, P>(Expression<Func<T, P>> expr)
{
MemberExpression me;
switch (expr.Body.NodeType)
{
case ExpressionType.Convert:
case ExpressionType.ConvertChecked:
var ue = expr.Body as UnaryExpression;
me = ((ue != null) ? ue.Operand : null) as MemberExpression;
break;
default:
me = expr.Body as MemberExpression;
break;
}
while (me != null)
{
string propertyName = me.Member.Name;
Type propertyType = me.Type;
Console.WriteLine(propertyName + ": " + propertyType);
me = me.Expression as MemberExpression;
}
}
I played a little with ExpressionVisitor:
public static class PropertyPath<TSource>
{
public static IReadOnlyList<MemberInfo> Get<TResult>(Expression<Func<TSource, TResult>> expression)
{
var visitor = new PropertyVisitor();
visitor.Visit(expression.Body);
visitor.Path.Reverse();
return visitor.Path;
}
private class PropertyVisitor : ExpressionVisitor
{
internal readonly List<MemberInfo> Path = new List<MemberInfo>();
protected override Expression VisitMember(MemberExpression node)
{
if (!(node.Member is PropertyInfo))
{
throw new ArgumentException("The path can only contain properties", nameof(node));
}
this.Path.Add(node.Member);
return base.VisitMember(node);
}
}
}
Usage:
var path = string.Join(".", PropertyPath<string>.Get(x => x.Length).Select(p => p.Name));
Old question, I know... but if it's only the names you need, an even simpler way to do it is:
expr.ToString().Split('.').Skip(1)
EDIT:
public class A
{
public B Property { get; set; }
}
public class B
{
public C field;
}
[Fact]
public void FactMethodName()
{
var exp = (Expression<Func<A, object>>) (x => x.Property.field);
foreach (var part in exp.ToString().Split('.').Skip(1))
Console.WriteLine(part);
// Output:
// Property
// field
}
I have a shared .NET standard DTO between client and server and expressions are a great way to create query strings that can be rebuilt and executed Api side.
A perfect way to create Type safe queries over the wire.
I digress, I needed a property path also
x => x.Siblings.Age
To produce a string like
"Siblings.Age"
I went with this
public static string GetMemberPath(MemberExpression me)
{
var parts = new List<string>();
while (me != null)
{
parts.Add(me.Member.Name);
me = me.Expression as MemberExpression;
}
parts.Reverse();
return string.Join(".", parts);
}
public static string GetPath<T, TProperty>(this Expression<Func<T, TProperty>> exp)
{
return string.Join(".", GetItemsInPath(exp).Reverse());
}
private static IEnumerable<string> GetItemsInPath<T, TProperty>(Expression<Func<T, TProperty>> exp)
{
if (exp == null)
{
yield break;
}
var memberExp = FindMemberExpression(exp.Body);
while (memberExp != null)
{
yield return memberExp.Member.Name;
memberExp = FindMemberExpression(memberExp.Expression);
}
}
I refactored these answers to use recursion, so no need for order reversal. I only need the property tree, so left out all but MemberExpressions. Should be simple to add functionality if need be.
public IEnumerable<string> PropertyPath<TModel, TValue>(
Expression<Func<TModel, TValue>> expression)
{
if (expression.Body is MemberExpression memberExpression)
return PropertyPathRecurse(memberExpression);
return Enumerable.Empty<string>();
}
private IEnumerable<string> PropertyPathRecurse(MemberExpression? expression)
{
if (expression is null)
return Enumerable.Empty<string>();
return PropertyPathRecurse(expression.Expression as MemberExpression)
.Append(expression.Member.Name);
}

Categories

Resources