2015-02-17 6 views
6

ich eine Klasse, die INotifyPropertyChanged wie folgt implementiert:Schalter-Kasten Class.PropertyName (nicht Wert)

public class Person : INotifyPropertyChanged { 

    public event PropertyChangedEventHandler PropertyChanged; 

    string _color; 
    public string Color 
    { 
     get{ return _color; } 
     set 
     { 
      _color = value; 
      RaisePropertyChanged(); 
     } 
    } 

    ...   

    private void RaisePropertyChanged([CallerMemberName]string prop = "") 
    { 
     if (PropertyChanged != null) 
      PropertyChanged(this, new PropertyChangedEventArgs(prop)); 
    } 
} 

Wenn die Color Eigenschaft Setter genannt wird, es RaisePropertyChanged() nennt, die automatisch den Eigenschaftsnamen dh "Color" bekommt und verwendet diese um PropertyChangedEventArgs zu füllen. Anstatt dass Sie den Eigenschaftsnamen manuell eingeben.

Das ist gut, weil es mögliche Fehler in Ihrem Code verhindert, da Sie den Eigenschaftsnamen nicht manuell eingeben müssen. Dies hilft auch beim Refactoring Ihres Codes, da Sie keine Strings codieren.

Meine Frage
Ich habe einen Event-Handler für PropertyChanged. Wie kann ich ein Switch-Case-Konstrukt verwenden, ohne die Eigenschaftsnamen als Strings hart zu codieren? So etwas wie das:

void Person_PropertyChanged(object sender, PropertyChangedEventArgs e){ 
    switch (e.PropertyName) 
    { 
     case PropertyNameOf(Person.Color); 
      //some stuff 
      break; 
     default: 
      break; 
    } 
} 

Ist das möglich? Ich möchte das tun, damit ich die Vorteile, die ich oben erwähnt habe, behalten kann.

+0

Was müssen Sie innerhalb des 'case' tun? –

+0

@NateBarbettini Einige Sachen. Ich habe es ausgelassen, weil ich denke, dass es für die Frage – Krimson

+3

nicht relevant war. Sie suchen nach C# 6 'nameof' -Operator. – SLaks

Antwort

7

Sie können Expression<Func<T>> verwenden, um zu tun, was Sie wollen.

definieren diese Methode:

private string ToPropertyName<T>(Expression<Func<T>> @this) 
{ 
    var @return = string.Empty; 
    if (@this != null) 
    { 
     var memberExpression = @this.Body as MemberExpression; 
     if (memberExpression != null) 
     { 
      @return = memberExpression.Member.Name; 
     } 
    } 
    return @return; 
} 

Dann folgendes schreiben:

void Person_PropertyChanged(object sender, PropertyChangedEventArgs e){ 
    switch (e.PropertyName) 
    { 
     case ToPropertyName(() => Person.Color); 
      //some stuff 
      break; 
     default: 
      break; 
    } 
} 

Jetzt haben Sie eine stark typisierte Freude. :-)


Um Schalter-ähnliche Funktionalität ohne switch und chaotisch if/then/else bekommen können Sie dies tun:

void Person_PropertyChanged(object sender, PropertyChangedEventArgs e) 
{ 
    var @switch = new Dictionary<string, Action>() 
    { 
     { ToPropertyName(() => Person.Color),() => { /* some stuff */ } }, 
     { ToPropertyName(() => Person.Size),() => { /* some other stuff */ } }, 
     { ToPropertyName(() => Person.Shape),() => { /* some more stuff */ } }, 
    }; 

    if (@switch.ContainsKey(e.PropertyName)) 
    { 
     @switch[e.PropertyName](); 
    } 
    else 
    { 
     /* default stuff */ 
    } 
} 
+0

Das ist brilliant. –

+0

Super! Danke vielmals! – Krimson

+0

Eine Frage.Wie können Sie 'Person.Color' machen, da' Color' ein nicht statisches Feld ist? – Krimson

5

In C# 6.0, können Sie das nameof() Schlüsselwort verwenden.

Das Schlüsselwort wird bei der Kompilierung durch Zeichenfolgenliterale ersetzt. So ist es viel besser als mit dem Code mit Lambda-Ausdruck, der den Namen des Symbols zur Laufzeit gräbt auf einer Performance-Sicht, und es funktioniert auch mit switch() Aussagen:

switch(e.PropertyName) 
{ 
    case nameof(Foo.Bar): 
     break; 
} 

Sie werden auch eine Kompilierung Fehlermeldung erhalten, wenn Sie ändern den Namen der Eigenschaft in der Klasse, vergessen jedoch, sie in Ihrer switch-Anweisung zu ändern. Dieser Ansatz ist also weniger fehleranfällig.