You have to change
var propertyName = ((PropertyExpression)expr.Left).Name;
to
var propertyName = ((MemberExpression)expr.Left).Member.Name;
and your code compiles, but what you do is not optimal and trusting at all. And you get an InvalidCastException !
Compiling Expression<T> for each call is not optimal, and as you can tell, the user passes the lambda to the method, for example:
() => (Id != value)
but not
() => (id != value)
or
() => (value != Id)
?
Also, the value in your expression is not ConstantExpression . value itself is a local variable in the set of the property, and when passed to a lambda expression, in the class field (the value is captured - see here for more information). So you have MemberExpression on both sides.
I highly recommend using this approach if you cannot use .NET 4.5 ( [CallerMemberName] ):
public class EntityBase : INotifyPropertyChanged { protected virtual void OnPropertyChanged(string propName) { var h = PropertyChanged; if (h != null) h(this, new PropertyChangedEventArgs(propName)); } public event PropertyChangedEventHandler PropertyChanged; protected bool ChangeAndNofity<T>(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; } field = value; OnPropertyChanged(body.Member.Name); return true; } }
Usage is simple:
public class Person : EntityBase { private int _id; public int Id { get { return _id; } set { ChangeAndNofity(ref _id, value, () => Id); } } }
Mohammad dehghan
source share