2015-02-17 8 views
6

ho una classe che implementa INotifyPropertyChanged come questo:switch-case su Class.PropertyName (non il valore)

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)); 
    } 
} 

Quando il setter Color proprietà viene chiamata, si chiama RaisePropertyChanged() che ottiene automaticamente il nome della proprietà cioè "Color" e lo usa per popolare PropertyChangedEventArgs. Invece di digitare manualmente il nome della proprietà.

Questo è utile perché impedisce possibili errori nel codice poiché non è necessario digitare manualmente il nome della proprietà. Aiuta anche nel refactoring del codice poiché non stai codificando le stringhe.

La mia domanda
Ho un gestore di eventi per PropertyChanged. Come posso utilizzare un costrutto switch-case senza hard-coding dei nomi di proprietà come stringhe. Quindi qualcosa del genere:

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

È possibile? Voglio fare questo in modo da poter mantenere i benefici che ho citato sopra.

+0

Cosa devi fare all'interno del 'caso'? –

+0

@NateBarbettini Alcune cose. L'ho lasciato fuori perché non penso fosse pertinente alla domanda – Krimson

+3

Stai cercando l'operatore 'nameof' del C# 6. – SLaks

risposta

7

È possibile utilizzare Expression<Func<T>> per fare ciò che si desidera.

definire questo metodo:

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; 
} 

Quindi è possibile scrivere questo:

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

Ora avete un po 'di gioia fortemente tipizzato. :-)


Per ottenere funzionalità di switch-like senza switch e disordinato if/then/else si può fare questo:

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

Questo è geniale. –

+0

Fantastico! Molte grazie! – Krimson

+0

Una domanda.Come fai a fare 'Person.Color' dato che' Color' è un campo non statico? – Krimson

5

In C# 6.0, è possibile utilizzare la parola chiave nameof().

La parola chiave è sostituita da stringhe letterali al momento della compilazione. Quindi è molto meglio che usare un'espressione lambda con il codice che scava il nome del simbolo in fase di esecuzione su un punto di vista delle prestazioni, e funziona anche con switch() dichiarazioni:

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

Si riceverà anche un errore di compilazione se si modifica il nome della proprietà nella classe, ma si dimentica di modificarlo nella propria istruzione switch. Quindi questo approccio è molto meno bugprone.

Problemi correlati