2009-07-14 6 views
10

プロパティの名前を変更し、INotifyPropertyChangedのPropertyChangedイベントのプロパティ名を除いて、Visual Studioの名前変更機能が必要なすべての名前変更を処理することが予期されるイベントです。あなたはそれを手動で名前を変更することを覚えておく必要はありませんので、何とか強く型付けされて取得するための良い方法はありますか?C#でPropertyChangedイベントを行うための強く型付けされた方法はありますか?

+0

(リクエスト/コメントごとに追加された例) –

+1

この記事をご覧ください。 http://weblogs.asp.net/dwahlin/archive/2009/07/07/validating-properties-in-silverlight-classes.aspx INotifyPropertyChangedを実装し、それから派生する基本クラスを作成する場合は、多分、これを使うことができます。 –

+1

INotifyPropertyChangedを実装するコンパイラがチェックした方法については、http://stackoverflow.com/questions/1329138/how-to-make-databinding-type-safe-and-support-refactoring/1333874#1333874を参照してください。プロパティ名が魔法の文字列であるのを避ける。 –

答えて

8

編集:nameofがC#6に到着しました。


にはnameof/infoofなどありません。これは多く議論されていますが、それはそれです。

.NET 3.5でラムダ式を使用して(そして式ツリーを解析する)方法がありますが、実際にはオーバーヘッドの価値はありません。今のところ、私は弦(とあなたがそれを壊さないことを決定した場合単体テスト)に固執します。


using System; 
using System.ComponentModel; 
using System.Linq.Expressions; 
using System.Reflection; 
class Program : INotifyPropertyChanged { 
    public event PropertyChangedEventHandler PropertyChanged; 
    static void Main() { 
     var p = new Program(); 
     p.PropertyChanged += (s, a) => Console.WriteLine(a.PropertyName); 
     p.Name = "abc"; 
    } 
    protected void OnPropertyChanged<T>(Expression<Func<Program, T>> property) { 
     MemberExpression me = property.Body as MemberExpression; 
     if (me == null || me.Expression != property.Parameters[0] 
       || me.Member.MemberType != MemberTypes.Property) { 
      throw new InvalidOperationException(
       "Now tell me about the property"); 
     } 
     var handler = PropertyChanged; 
     if (handler != null) handler(this, 
      new PropertyChangedEventArgs(me.Member.Name)); 
    } 
    string name; 
    public string Name { 
     get{return name;} 
     set { 
      name = value; 
      OnPropertyChanged(p=>p.Name); 
     } 
    } 
} 
+0

私はおそらく文字列に固執するでしょうが、キックのために、表現木を解析する方法の短いコードサンプルを与えることができますか? – Davy8

+0

なぜ 'Expression 'と '()=> Name'ではなく' Expression > 'と' p => p.Name'を使うのですか? – Svish

+1

どちらかというとうまくいくかもしれませんが、ポストされたバージョンは、インスタンス上のプロパティーを探していることを明らかにしています。 –

0

あなたの質問には答えられませんが、右クリック - >リファクタリング - >プロパティの名前を変更すると、プロパティ名に一致する文字列も含めて一致する文字列の名前を変更できます。

ええ、それは少し危険です。

+0

コメントの名前を変更することは危険です。私は、この機能が名前を変更するコード要素のコメントにスコープを制限すると仮定して、むしろ大規模なプロジェクトでXML文書の束を混乱させました。 – snarf

-1

PropertyChangedEventArgsは、プロパティ名を文字列として必要とするコンストラクタを1つだけ使用します。つまり、INotifyPropertyChangedを本質的に利用しないということは、あるレベルではアーキテクチャーの高低にかかわらず、文字列と手動で名前を変更する必要があります。

2

最も簡単な解決策は、スタックトレースを見て、completlyプロパティへのすべての明示的な参照を削除することです。 set_<PropertyName>という名前のプロパティのセッターメソッドである -

public String Name 
{ 
    get { return this.name; } 
    set 
    { 
     if (value != this.name) 
     { 
      this.RaisePropertyChanging(); 
      this.name = value; 
      this.RaisePropertyChanged(); 
     } 
    } 
} 
private String name = null; 

private void RaisePropertyChanged() 
{ 
    String propertyName = 
     new StackTrace().GetFrame(1).GetMethod().Name.SubString(4); 

    PropertyChangedEventHandler handler = this.PropertyChanged; 
    if (handler != null) 
    { 
     handler(new PropertyChangedEventArgs(propertyName)); 
    } 
} 

コードがcaling方法からスタックトレースを通じてプロパティ名を導出します。コンパイラがこの命名規則に従わなくなった場合、コードが破損します。

もう1つの解決策は、ラムダ式からプロパティ名を派生させることです。例

GetPropertyNameFromLambdaExpression<String, Int32>(s => s.Length) 

については

public static String GetPropertyNameFromLambdaExpression<TObject, TProperty>(
    Expression<Func<TObject, TProperty>> expression) 
{ 
    return ((MemberExpression)expression.Body).Member.Name; 
} 

exspectedとして "Length" を返します。本番版のコードは、実際には追加のチェックとコードの残りの部分への統合が必要です。たとえば、汎用引数の型推論を使用することができます。

UPDATE

そして第三に解決策があります - あなたは、セッターやゲッターメソッドの名前を取得するプロパティのゲッターやセッターの内側MethodBase.GetCurrentMethod()を使用することができます。

public String Name 
{ 
    get { return this.name; } 
    set 
    { 
     if (value != this.name) 
     { 
      String propertyName = MethodBase.GetCurentMethod().Name.SubString(4); 

      this.RaisePropertyChanging(propertyName); 
      this.name = value; 
      this.RaisePropertyChanged(propertyName); 
     } 
    } 
} 
private String name = null; 
+1

この解決方法は、単にプロパティ名を文字列として設定するよりも脆弱です。 – Charlie

+0

これは面白そうです。ドキュメントをチェックせずに、私はSubStringへの呼び出しが何であるかを理解することはできません。 GetMethod()。Nameは何か奇妙なものを返しますか? –

+0

プロパティは2つのメソッドによって実装されます。 public MyType MyProperty {get;セット; }は、public void set_MyProperty(MyType value){}およびpublic MyType get_MyProperty()として実装されています。したがって、返されたメソッド名からset_とget_を削除して、プロパティの名前を取得する必要があります。 –

1

理論上、プロパティセッター内では、MethodBase.GetCurrentMethod()。Name.Substring(4)を使用できます。残念ながら、Google検索ではit seems to have a significant performance impactと表示されます。考慮すべきもう2つの事項:

  • JITインライン化は、予期しない方法でこれに影響を与える可能性があります。理論的には、MethodBase.GetCurrentMethod()へのIL呼び出しを簡単に置き換えることができました(理論的には、MethodBase.GetCurrentMethod実行時にJITによってldtoken命令とそれに続くMethodBase.GetMethodFromHandle()への呼び出しがあり、非常に高速です。私はユーザーがちょうどこれの必要性を表明していないと思います。 (msdn.microsoft.com/en-us/library/system.reflection.emit.opcodes.ldtoken.aspx)
  • 完全に私の意見はここですが、fieldof()とmethodof() C#の演算子。その能力を必要とするプロジェクトでコード分析/リファクタリングツールの信頼性を大幅に向上させると私は信じています。
0

あなたはblog postをチェックアウトする必要があります。

string propertyName = TypeHelper.GetPropertyName<User>(u => u.LastProjectCode); 

PropertyInfo property1 = TypeHelper.GetProperty((SomeClass o) => o.InstanceProperty.Length); 

PropertyInfo property2 = TypeHelper.GetProperty(() => SomeClass.StaticProperty.Length); 

Visual Studio/Resharper/Refactor Proの名前を変更する必要があります。

6

C#5には解決策があるようです。パラメータOne example on the netで使用できるCallerMemberName attributeがあります。

class Employee : INotifyPropertyChanged 
{ 
    private string _Name; 
    public string Name 
    { 
     get { return _Name; } 

     set 
     { 
      _Name = value; 
      RaisePropertyChanged(); 
     } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    private void RaisePropertyChanged([CallerMemberName] string caller = "") 
    { 
     var temp = PropertyChanged; 

     if (temp != null) 
     { 
      temp(this, new PropertyChangedEventArgs(caller)); 
     } 
    } 
} 
+0

うわー!あなたのものは一番クールだそうです。 – VivekDev

関連する問題