c# – 使用ExpressionTree分配属性

c# – 使用ExpressionTree分配属性,第1张

概述我正在玩一个将属性分配传递给方法作为表达式树的想法.该方法将调用表达式,以便正确分配属性,然后嗅出刚分配的属性名称,以便可以引发PropertyChanged事件.这个想法是,我希望能够在我的 WPF ViewModels中使用超薄的自动属性,并且仍然关闭PropertyChanged事件. 我是ExpressionTrees的无知,所以我希望有人能指出我正确的方向: public class V 我正在玩一个将属性分配传递给方法作为表达式树的想法.该方法将调用表达式,以便正确分配属性,然后嗅出刚分配的属性名称,以便可以引发PropertyChanged事件.这个想法是,我希望能够在我的 WPF viewmodels中使用超薄的自动属性,并且仍然关闭PropertyChanged事件.

我是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分配属性所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址:https://www.54852.com/langs/1239027.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-06-06
下一篇2022-06-06

发表评论

登录后才能评论

评论列表(0条)

    保存