C# 如何分解表达式以满足泛型属性更改方法?
我有一个基本EF实体类,它实现了C# 如何分解表达式以满足泛型属性更改方法?,c#,expression,inotifypropertychanged,C#,Expression,Inotifypropertychanged,我有一个基本EF实体类,它实现了INotifyPropertyChanged 基本属性Id是我的示例: /// <summary> /// Entity Id /// </summary> public int Id { get { return id; } set { SetValue<int>(() => (Id != value), (v) => id = v); } // < can this be
INotifyPropertyChanged
基本属性Id是我的示例:
/// <summary>
/// Entity Id
/// </summary>
public int Id {
get { return id; }
set { SetValue<int>(() => (Id != value), (v) => id = v); } // < can this be simplified into a single call?
}
//
///实体Id
///
公共整数Id{
获取{return id;}
set{SetValue(()=>(Id!=value),(v)=>Id=v);}/<这可以简化为单个调用吗?
}
…其中定义了SetValue:
protected void SetValue<TValue>(Expression<Func<bool>> evalExpr, Action<TValue> set) {
// Compile() returns a Func<bool>
var doSetValue = evalExpr.Compile();
if (doSetValue()) {
var expr = evalExpr.Body as BinaryExpression;
// this is not compiling - how do I decompose the expression to get what I need?
var propertyName = ((PropertyExpression)expr.Left).Name;
var assignValue = (TValue)((ConstantExpression)expr.Right).Value;
set(assignValue);
_propertyChangedHandler(this, new PropertyChangedEventArgs(propertyName));
}
}
protectedvoid SetValue(表达式evalExpr,动作集){
//Compile()返回一个Func
var doSetValue=evalExpr.Compile();
if(doSetValue()){
var expr=evalExpr.Body作为二进制表达式;
//这不是编译-如何分解表达式以获得所需内容?
var propertyName=((PropertyExpression)expr.Left).Name;
var assignValue=(TValue)((ConstantExpression)expr.Right)值;
设定(赋值);
_propertyChangedHandler(这是新的PropertyChangedEventArgs(propertyName));
}
}
我能找到的所有样本都需要参数。我希望setter(SetValue调用)尽可能简单,也就是说,有没有办法将输入参数减少到1?有各种选项比您得到的选项更简单(以下是我对每个选项的喜好程度的大致顺序):
- -这是一个免费的自动代码编织器,在编译时运行,以自动实现对所选类的属性的
。运行时不需要任何程序集INotifyPropertyChanged
protected bool SetProperty(ref T storage,T value,[CallerMemberName]String propertyName=null)
{
if(object.Equals(storage,value))返回false;
储存=价值;
此.OnPropertyChanged(propertyName);
返回true;
}
用法如下:
/// <summary>
/// Entity Id
/// </summary>
public int Id {
get { return id; }
set { SetValue(ref id, value); }
}
//
///实体Id
///
公共整数Id{
获取{return id;}
set{SetValue(ref id,value);}
}
您应该更改
var propertyName = ((PropertyExpression)expr.Left).Name;
到
您的代码可以编译,但您所做的根本不是最佳的和可信的。您将得到一个无效的castexception
在每次调用时编译表达式
不是最优的,您如何判断用户是否将lambda传递给如下方法:
() => (Id != value)
而不是
() => (id != value) // using the field instead of property
或
?
此外,表达式中的值
不是常量表达式
。值
本身只是属性的集合
部分的局部变量,当传递到lambda表达式时,会提升到类字段(捕获值-有关详细信息,请参阅)。因此,两边都有一个MemberExpression
如果您不能使用.NET 4.5([CallerMemberName]
),我强烈建议您使用这种方法:
嗯……还不能完全使用.NET4.5。我将仔细阅读参考资料,寻找与.NET4.0兼容的解决方案。谢谢,关于信任的观点很好。我目前正在使用更多的参数来确保正确遵守SetValue方法的意图。谢谢。奖金…更好的通知。谢谢你,先生!
() => (Id != value)
() => (id != value) // using the field instead of property
() => (value != Id) // passing the property as the second operand
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;
}
}
public class Person : EntityBase
{
private int _id;
public int Id
{
get { return _id; }
set { ChangeAndNofity(ref _id, value, () => Id); }
}
}