Switch-Case on Class.PropertyName (not value)

孤街浪徒 提交于 2021-02-06 09:25:02

问题


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.


回答1:


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



回答2:


In C# 6.0, you can use the nameof() keyword.

The keyword is replaced by string literals at compile time. So it's much better than using lambda expression with code that digs the name of your symbol at runtime on a performance point of view, and it also works with switch() statements:

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

You will also get a compile time error if you change the name of the property in the class, but forget to change it in your switch statement. So this approach is much less bugprone.



来源:https://stackoverflow.com/questions/28553967/switch-case-on-class-propertyname-not-value

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!