1

使用 WPF 使我成为 INotifyPropertyChanged 的​​粉丝。我喜欢使用一个辅助函数,它接受一个表达式并将名称作为字符串返回(参见下面的示例代码)。然而,在我看到的非常熟练的程序员所看到的许多应用程序中,我看到了处理原始字符串的代码(参见下面的第二个示例)。我所说的精通是指知道如何使用表达式的 MVP 类型。

对我来说,除了简单的重构之外,让编译器捕获错误的机会使 Exression 方法更好。是否有支持使用我遗漏的原始字符串的论点?

干杯,贝里尔

表达式助手示例:

public static string GetPropertyName<T>(Expression<Func<T, object>> propertyExpression)
    {
        Check.RequireNotNull<object>(propertyExpression, "propertyExpression");
        switch (propertyExpression.Body.NodeType)
        {
            case ExpressionType.MemberAccess:
                return (propertyExpression.Body as MemberExpression).Member.Name;
            case ExpressionType.Convert:
                return ((propertyExpression.Body as UnaryExpression).Operand as MemberExpression).Member.Name;
        }
        var msg = string.Format("Expression NodeType: '{0}' does not refer to a property and is therefore not supported", 
            propertyExpression.Body.NodeType);
        Check.Require(false, msg);
        throw new InvalidOperationException(msg);
    }

原始字符串示例代码(在某些 ViewModelBase 类型类中):

        /// <summary>
    /// Warns the developer if this object does not have
    /// a public property with the specified name. This 
    /// method does not exist in a Release build.
    /// </summary>
    [Conditional("DEBUG"), DebuggerStepThrough]

    public void VerifyPropertyName(string propertyName) {
        // Verify that the property name matches a real,  
        // public, instance property on this object.
        if (TypeDescriptor.GetProperties(this)[propertyName] == null) {
            string msg = "Invalid property name: " + propertyName;

            if (ThrowOnInvalidPropertyName) throw new Exception(msg);
            else Debug.Fail(msg);
        }
    }

    /// <summary>
    /// Returns whether an exception is thrown, or if a Debug.Fail() is used
    /// when an invalid property name is passed to the VerifyPropertyName method.
    /// The default value is false, but subclasses used by unit tests might 
    /// override this property's getter to return true.
    /// </summary>
    protected virtual bool ThrowOnInvalidPropertyName { get; private set; }
4

5 回答 5

4

对我来说,除了简单的重构之外,让编译器捕获错误的机会使 Exression 方法更好。是否有支持使用我遗漏的原始字符串的论点?

在大多数情况下,我同意并且就个人而言,在我自己的代码中使用表达式方法。

但是,我知道有两个原因可以避免这种情况:

  1. 这不太明显,尤其是对于经验不足的 .NET 开发人员而言。写作RaisePropertyChanged(() => this.MyProperty );对人们来说并不总是那么明显RaisePropertyChanged("MyProperty");,并且与框架示例等不匹配。

  2. 使用表达式有一些性能开销。就个人而言,我不认为这是一个真正有意义的原因,因为这通常用于数据绑定场景(由于反射使用已经很慢),但它可能是一个有效的问题。

于 2009-11-02T21:02:40.717 回答
2

使用该TypeDescriptor方法的好处是它支持基于 ICustomTypeDescriptor 实现的动态属性场景,其中实现可以有效地为正在描述的类型动态创建动态属性元数据。例如,考虑一个 DataSet,其“属性”由填充它的结果集决定。

然而,这是表达式不提供的东西,因为它基于实际的类型信息(一件好事)而不是字符串。

于 2009-11-02T21:08:00.350 回答
1

我最终在这方面花费的时间比我预期的要多,但确实找到了一个兼具安全性/可重构性和性能的解决方案。良好的背景阅读和使用反射的替代解决方案在这里。我更喜欢 Sacha Barber 的解决方案(背景在这里.

这个想法是为将参与更改通知的属性使用表达式帮助器,但通过将生成的 PropertyChangedEventArgs 存储在您的视图模型中,只对其进行一次点击。例如:

private static PropertyChangedEventArgs mobilePhoneNumberChangeArgs =
        ObservableHelper.CreateArgs<CustomerModel>(x => x.MobilePhoneNumber);

HTH,
绿柱石

于 2009-11-11T23:54:21.010 回答
0

.net 4.5 中引入了 CallerMemberName 属性此属性只能附加到可选的字符串参数,如果调用者在函数调用中未使用该参数,则调用者的名称将在字符串参数中传递

这消除了在引发 PropertyChanged 事件时指定属性名称的需要,因此它适用于重构,并且由于更改是在编译时完成的,因此性能没有差异。

下面是一个实现示例,更多信息可以在http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.callermembernameattribute.aspxhttp://msdn.microsoft.com/en找到-我们/图书馆/hh534540.aspx

    public class DemoCustomer : INotifyPropertyChanged
    {
        string _customerName
        public string CustomerName
        {
            get { return _customerNameValue;}
            set
            {
                if (value != _customerNameValue)
                {
                    _customerNameValue = value;
                    NotifyPropertyChanged();
                }
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
于 2013-07-07T23:53:28.767 回答
0

Stack walk 很慢,而 lambda 表达式甚至更慢。我们有类似于众所周知的 lambda 表达式的解决方案,但几乎与字符串文字一样快。见 http://zamboch.blogspot.com/2011/03/raising-property-changed-fast-and-safe.html

于 2011-03-26T20:26:16.897 回答