重构大型交换机语句

问题描述 投票:0回答:3

我已经编写了此方法,该方法根据表单提交的用户输入来“猜测”某种费用,以将真棒字体图标应用于该方法-在调用此方法之前已完成验证。如果没有条件匹配,则返回通用图标:

public static class IconService
{
    public static string GuessExpenseIcon(string input)
    {
        string expenseName = input.ToLower();
        string expenseIcon;

        switch (expenseName)
        {
            case string a when a.Contains("phone"):
            case string b when b.Contains("mobile"):
                expenseIcon = "fas fa-mobile-alt";
                break;

            case string a when a.Contains("rent"):
            case string b when b.Contains("mortgage"):
            case string c when c.Contains("house"):
            case string d when d.Contains("flat"):
            case string e when e.Contains("apartment"):
                expenseIcon = "fas fa-home";
                break;

            case string a when a.Contains("gas"):
            case string b when b.Contains("util"):
                expenseIcon = "fas fa-burn";
                break;

            case string a when a.Contains("electric"):
            case string b when b.Contains("power"):
                expenseIcon = "fas fa-bolt";
                break;

            case string a when a.Contains("petrol"):
            case string b when b.Contains("diesel"):
            case string c when c.Contains("fuel"):
                expenseIcon = "fas fa-gas-pump";
                break;

            case string a when a.Contains("food"):
            case string b when b.Contains("groceries"):
            case string c when c.Contains("eat"):
            case string d when d.Contains("take"):
                expenseIcon = "fas fa-utensils";
                break;

            case string a when a.Contains("water"):
                expenseIcon = "fas fa-shower";
                break;

            case string a when a.Contains("car"):
            case string b when b.Contains("van"):
                expenseIcon = "fas fa-car";
                break;

            case string a when a.Contains("internet"):
            case string b when b.Contains("network"):
                expenseIcon = "fas fa-wifi";
                break;

            case string a when a.Contains("spotify"):
                expenseIcon = "fab fa-spotify";
                break;

            case string a when a.Contains("bus"):
            case string b when b.Contains("coach"):
                expenseIcon = "fas fa-bus";
                break;

            case string a when a.Contains("charity"):
            case string b when b.Contains("donation"):
                expenseIcon = "fas fa-hand-holding-heart";
                break;

            case string a when a.Contains("aws"):
                expenseIcon = "fab fa-aws";
                break;

            default:
                expenseIcon = "fas fa-money-bill-alt";
                break;
        }

        return expenseIcon;
    }
}

我的问题是:这么大的switch语句是实现这一目标的最佳方法吗?

我知道我可能只是过早地进行优化,因为我没有注意到负面的性能,但是由于某种原因,它对我来说似乎不合适。

c# .net-core switch-statement
3个回答
2
投票

我将定义一个词典并使用它:

public static class IconService
{
    private static Dictionary<string, string> _expenseIcons = new Dictionary<string, string(StringComparer.OrdinalIgnoreCase) {
        { "phone", "fa-mobile-alt" },
        { "mobile", "fa-mobile-alt" },
        { "rent", "fa-mobile-alt" },
        { "mortgage", "fa-mobile-alt" },
        { "house", "fa-mobile-alt" },
        { "flat", "fa-mobile-alt" },
        { "apartment", "fa-mobile-alt" }
        /* etc */
    };

    public static string GuessExpenseIcon(string input)
    {
        if (_expenseIcons.TryGetValue(input, out string expenseIcon)) // if the icon is found in the dictionary
        {
            return $"fas {expenseIcon}";
        }

        // default
        return "fas fa-money-bill-alt";
    }
}

我已经为字典键使用了不区分大小写的字符串比较器,因此您无需执行.ToLower()位。我还从我们在词典中存储的内容中删除了图标的常见“ fas”部分,因为每个图标都有它。

我认为这不一定比您的switch语句更好,但是这是一种更为优雅的解决方案,它还为更改_expenseIcons的配置方式提供了可能性。例如,您可以从配置文件等中加载它。

就效率而言,我们将在应用程序/ appdomain的整个生命周期中初始化一次字典。字典本身的efficiency of lookups接近O(1):

通过使用其键检索值非常快,接近O(1),因为Dictionary<TKey,TValue>类被实现为哈希表。


0
投票

怎么样?

class MatchPattern
{
    public string [] Patterns {get;set;}

    // This is to asume that you have more logic 
    // If all the logic of GetIcon is to return a simple string, you can
    // replace with 
    //  public string IconName {get;set;}
    // instead.
    public Func<string, string> GetIcon {get;set;}
}

public class IconService
{
    private MatchPatterns[] _patterns;
    public IconService()
    {
        _patterns=new []
        {
            new MatchPattern
            {
                Patterns=new[]{"phone", "mobile"},
                GetIcon=(x)=>"fas fa-mobile-alt"
            },
            new MatchPattern
            {
                Patterns=new[]{"rent", "mortgage", "house", "flat", "apartment"},
                GetIcon=(x)=>"fas fa-home"
            }
            , 
            // Here is more
        }
    }
    public static string GuessExpenseIcon(string input)
    {
        foreach(var pattern in _patterns)
        {
            if(pattern.Any(item=>input.contains(item))
            {
                return pattern.GetIcon.Invoke(input);
            }
        }

    }
}

使用Func可以解决以下情况:在不同情况下,您仍然具有一些稍微不同的逻辑。如果不是这种情况,则可以使用简单的IconName代替GetIcon Func。

class MatchPattern
{
    public string [] Patterns {get;set;}

    public string IconName {get;set;}
}

0
投票

您可以处理每种情况的列表

foreach (var str in new string[] { "phone","mobile" }) {
    if (expenseName.Contains(str)){
        expenseIcon = "fas fa-mobile-alt";
    }
}

也许值得研究Lambda表达式,这些表达式在Java中的语法较短,但是我不确定C#对它的支持程度如何

© www.soinside.com 2019 - 2024. All rights reserved.