
我是ExpressionTrees的无知,所以我希望有人能指出我正确的方向:
public class viewmodelBase { public event Action<string> PropertyChanged = delegate { }; public int Value { get; set; } public voID RunAndRaise(MemberAssignment Exp) { Expression.Invoke(Exp.Expression); PropertyChanged(Exp.Member.name); }} 问题是我不知道如何调用这个.这个天真的尝试被编译器拒绝了,因为我肯定会对任何可以回答这个问题的人显而易见的:
viewmodelBase vm = new viewmodelBase(); vm.RunAndRaise(() => vm.Value = 1);
编辑
谢谢@svick的完美答案.我移动了一个小东西,把它变成一个扩展方法.以下是单元测试的完整代码示例:
[TestClass]public class UnitTest1 { [TestMethod] public voID TestMethod1() { Myviewmodel vm = new Myviewmodel(); bool ValuePropertyRaised = false; vm.PropertyChanged += (s,e) => ValuePropertyRaised = e.Propertyname == "Value"; vm.SetValue(v => v.Value,1); Assert.AreEqual(1,vm.Value); Assert.IsTrue(ValuePropertyRaised); }}public class viewmodelBase : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged = delegate { }; public voID OnPropertyChanged(string propertyname) { PropertyChanged(this,new PropertyChangedEventArgs(propertyname)); }}public class Myviewmodel : viewmodelBase { public int Value { get; set; }}public static class viewmodelBaseExtension { public static voID SetValue<Tviewmodel,TProperty>(this Tviewmodel vm,Expression<Func<Tviewmodel,TProperty>> exp,TProperty value) where Tviewmodel : viewmodelBase { var propertyInfo = (PropertyInfo)((MemberExpression)exp.Body).Member; propertyInfo.SetValue(vm,value,null); vm.OnPropertyChanged(propertyInfo.name); }}解决方法 你不能这样做.首先,lambda表达式只能转换为委托类型或表达式. 如果将方法的签名(现在忽略其实现)更改为public voID RunAndRaise(Expression< Action> Exp),则编译器会抱怨“表达式树可能不包含赋值运算符”.
您可以通过使用lambda指定属性并将其设置为另一个参数的值来执行此 *** 作.此外,我没有找到一种方法从表达式访问vm的值,所以你必须把它放在另一个参数(你不能使用这个,因为你需要正确的继承类型在表达式中) :看编辑
public static voID SetAndRaise<Tviewmodel,TProperty>( Tviewmodel vm,TProperty value) where Tviewmodel : viewmodelBase{ var propertyInfo = (PropertyInfo)((MemberExpression)exp.Body).Member; propertyInfo.SetValue(vm,null); vm.PropertyChanged(propertyInfo.name);} 另一个可能性(和我更喜欢的一个)是使用这样的lambda来特别提出来自setter的事件:
private int m_value;public int Value{ get { return m_value; } set { m_value = value; RaisePropertyChanged(this,vm => vm.Value); }}static voID RaisePropertyChanged<Tviewmodel,TProperty>> exp) where Tviewmodel : viewmodelBase{ var propertyInfo = (PropertyInfo)((MemberExpression)exp.Body).Member; vm.PropertyChanged(propertyInfo.name);} 这样,您可以像往常一样使用属性,如果有的话,您还可以为计算属性引发事件.
编辑:在阅读Matt Warren’s series about implementing IQueryable<T>时,我意识到我可以访问引用的值,这简化了RaisePropertyChanged()的使用(尽管它不会对您的SetAndRaise())有所帮助:
private int m_value;public int Value{ get { return m_value; } set { m_value = value; RaisePropertyChanged(() => Value); }}static voID RaisePropertyChanged<TProperty>(Expression<Func<TProperty>> exp){ var body = (MemberExpression)exp.Body; var propertyInfo = (PropertyInfo)body.Member; var vm = (viewmodelBase)((ConstantExpression)body.Expression).Value; vm.PropertyChanged(vm,new PropertyChangedEventArgs(propertyInfo.name));} 总结 以上是内存溢出为你收集整理的c# – 使用ExpressionTree分配属性全部内容,希望文章能够帮你解决c# – 使用ExpressionTree分配属性所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)