Class.PropertyName上的Switch-Case(非值)

时间:2015-02-17 03:00:57

标签: c# .net-4.5

我有一个实现INotifyPropertyChanged的类:

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

当调用Color属性设置器时,它会调用RaisePropertyChanged()自动获取属性名称"Color"并使用它来填充PropertyChangedEventArgs。而不是手动输入属性名称。

这很好,因为它可以防止代码中出现可能的错误,因为您不必手动输入属性名称。在重构代码时也很有帮助,因为你没有对任何字符串进行硬编码。

我的问题
我有PropertyChanged的事件处理程序。如何在不将Property Names硬编码为字符串的情况下使用switch-case结构。所以像这样:

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

这可能吗?我想这样做,所以我可以保留上面提到的好处。

2 个答案:

答案 0 :(得分:7)

您可以使用Expression<Func<T>>做您想做的事。

定义此方法:

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

然后你可以这样写:

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

现在你有一些强烈的喜悦。 : - )


要在没有switch和凌乱if / then / else的情况下获得类似交换机的功能,您可以这样做:

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

答案 1 :(得分:5)

在C#6.0中,您可以使用nameof()关键字。

在编译时,关键字由字符串文字替换。所以它比使用lambda表达式和在运行时在性能观点上挖掘符号名称的代码要好得多,而且它也适用于switch()语句:

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

如果更改了类中属性的名称,也会出现编译时错误,但忘记在switch语句中更改它。所以这种方法更不用说bug。