1

WPFを使用することで、INotifyPropertyChangedのファンになりました。式を受け取り、名前を文字列として返すヘルパーを使用するのが好きです(以下のサンプルコードを参照)。しかし、非常に熟練したプログラマーが目にする多くのアプリケーションでは、文字列を生で処理するコードが見られます(以下の2番目の例を参照)。熟練とは、エクスプレッションの使い方を知っている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アプローチをより良くします。私が見逃している生の文字列を使用することに賛成する議論はありますか?

私は同意し、個人的には、ほとんどの場合、自分のコードで式のアプローチを使用します。

ただし、これを回避するために私が知っている2つの理由があります。

  1. 特に経験の浅い.NET開発者にとっては、それほど明白ではありません。書くRaisePropertyChanged(() => this.MyProperty );ことは、人々にとって必ずしも明白RaisePropertyChanged("MyProperty");であるとは限らず、フレームワークのサンプルなどと一致しません。

  2. 式を使用すると、パフォーマンスのオーバーヘッドが発生します。個人的には、これは通常、データバインディングシナリオ(リフレクションの使用のためにすでに遅い)で使用されるため、これが理由としてそれほど意味があるとは思いませんが、潜在的に有効な懸念事項です。

于 2009-11-02T21:02:40.717 に答える
2

このアプローチを使用する利点は、TypeDescriptorICustomTypeDescriptor実装に基づく動的プロパティのシナリオが可能になり、実装が記述されているタイプの動的プロパティメタデータをその場で効果的に作成できることです。たとえば、「プロパティ」が入力された結果セットによって決定されるデータセットについて考えてみます。

ただし、これは、文字列ではなく実際の型情報(良いこと)に基づいているため、式では提供されないものです。

于 2009-11-02T21:08:00.350 に答える
1

予想以上に多くの時間を費やすことになりましたが、安全性/リファクタリング性とパフォーマンスがうまく組み合わされたソリューションを見つけました。優れたバックグラウンドリーディングとリフレクションを使用した代替ソリューションはこちらです。私はSachaBarberのソリューションがさらに好きです(背景はこちら) 。

アイデアは、変更通知に参加するプロパティに式ヘルパーを使用することですが、結果のPropertyChangedEventArgsをビューモデルに格納することにより、ヒットを1回だけ取得します。例えば:

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

HTH、
ベリール

于 2009-11-11T23:54:21.010 に答える
0

スタックウォークは遅く、ラムダ式はさらに遅くなります。よく知られているラムダ式に似ていますが、文字列リテラルとほぼ同じ速度のソリューションがあります。http://zamboch.blogspot.com/2011/03/raising-property-changed-fast-and-safe.htmlを参照してください

于 2011-03-26T20:26:16.897 に答える
0

CallerMemberName属性は.net4.5で導入されました。この属性はオプションの文字列パラメーターにのみ付加できます。パラメーターが関数呼び出しで呼び出し元によって使用されない場合、呼び出し元の名前が文字列パラメーターで渡されます。

これにより、PropertyChangedイベントを発生させるときにプロパティの名前を指定する必要がなくなり、リファクタリングで機能します。変更はコンパイル時に行われるため、パフォーマンスに違いはありません。

以下は実装の例です。詳細については、 http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.callermembernameattribute.aspxおよびhttp://msdn.microsoft.com/enを参照してください。 -us / library / 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 に答える