Krimson Krimson - 1 month ago 16
C# Question

Switch-Case on Class.PropertyName (not value)

I have a class which implements

INotifyPropertyChanged
like this:

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


When the
Color
property setter is called, it calls
RaisePropertyChanged()
which automatically gets the property name i.e
"Color"
and uses that to populate
PropertyChangedEventArgs
. Instead of you manually typing in the property name.

This is good because it prevents possible bugs in your code since you dont have to manually type the property name. Also helps when refactoring your code since you aren't hard-coding any strings.

My Question

I have an event handler for
PropertyChanged
. How can I use a switch-case construct without hard-coding the Property Names as strings. So something like this:

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


Is this possible? I want to do this so I can keep the benefits I mentioned above.

Answer

You can use Expression<Func<T>> to do what you want.

Define this method:

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

Then you can write this:

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

Now you have some strongly-typed joy. :-)


To get switch-like functionality without switch and messy if/then/else you can do this:

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 */
    }
}