更改枚举菜单名称格式 [C#]

Alter Enumeration Menu Name Format [C#]

我在格式化我特别希望将枚举项显示到控制台的方式时遇到问题 window。

截至目前,Menu 方法显示枚举中的项目如下:

[1] CreateCustomer
[2] CreateAccount
[3] SetAccountBalance
[4] DisplayAccount Balance
[5] Exit

我想要完成的是在每个菜单选项之间添加适当的空格。例如, "CreateCustomer" 到 "Create Customer"、"SetAccountBalance" 到 "Set Account Balance"。

菜单选择枚举

enum MenuSelection
{
   CreateCustomer = 1,
   CreateAccount = 2,
   SetAccountBalance = 3,
   DisplayAccountBalance = 4,
   Exit = 5,
   MaxMenuSelection = 5,
}

显示菜单方法

public static void Menu()
{
  for (int i = 1; i <= (int)MenuSelection.MaxMenuSelection; i++)
  {
     Console.WriteLine($"[{i}] {((MenuSelection)i).ToString()}");
  }
}

有什么建议吗?

我会使用 DictionarykeyMenuSelectionvalue 包含您的客户显示字符串。

Dictionary<MenuSelection, string> dict = new Dictionary<MenuSelection, string>();
dict.Add(MenuSelection.CreateCustomer, "Create Customer");
dict.Add(MenuSelection.CreateAccount, "Create Account");
dict.Add(MenuSelection.SetAccountBalance, "Set Account Balance");
dict.Add(MenuSelection.DisplayAccountBalance, "Display Account Balance");
dict.Add(MenuSelection.Exit, "Exit");

string showValue = string.Empty;
for (int i = 1; i <= (int)MenuSelection.MaxMenuSelection; i++)
{
    if (dict.TryGetValue((MenuSelection)i, out showValue))
    {
        Console.WriteLine($"[{i}] { showValue}");
    }           
}

一种方法是使用显示属性:

enum MenuSelection
{
   [Display(Name = "Create Customer")]
   CreateCustomer = 1,
   [Display(Name = "Create Account")]
   CreateAccount = 2,
   ...
}

但获得它的价值并不像它应该的那么容易。你可以在 How to get the Display Name Attribute of an Enum member via MVC razor code?

中找到它

我自己使用的另一种方法是我编写的一个函数,它在每个大写字母前添加一个 space:

public static class Exts
{ 
    public static string CapitalSplit(this string x)
    {
         return Regex.Replace(x, "([a-z])([A-Z])", " ").Trim();
    }
}

然后你可以像这样使用它:

 for (int i = 1; i <= (int)MenuSelection.MaxMenuSelection; i++)
 {
     Console.WriteLine($"[{i}] {((MenuSelection)i).ToString().CapitalSplit()}");
 }

您可以使用反射来获取Description 属性(或Display 属性)。这里我用了一个扩展的方法,让它更简单一些:

class Program
{
    static void Main(string[] args)
    {
        for (int i = 1; i <= (int)MenuSelection.MaxMenuSelection; i++)
        {
            Console.WriteLine($"[{i}] {((MenuSelection)i).GetEnumDescription()}");
        }

        Console.ReadLine();
    }
}

public static class Extensions
{
    public static string GetEnumDescription(this MenuSelection m)
    {
        FieldInfo fi = m.GetType().GetField(m.ToString());

        DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);

        return attributes != null && attributes.Length > 0 ? attributes[0].Description : m.ToString();
    }
}

public enum MenuSelection
{
    [Description("Create Customer")]
    CreateCustomer = 1,
    [Description("Create Account")]
    CreateAccount = 2,
    [Description("Set Account Balance")]
    SetAccountBalance = 3,
    [Description("Display Account Balance")]
    DisplayAccountBalance = 4,
    Exit = 5,
    MaxMenuSelection = 5,
}

结果:

[1] Create Customer
[2] Create Account
[3] Set Account Balance
[4] Display Account Balance
[5] Exit

你可以这样做

using System;
using System.Linq;
using System.Collections.Generic;

public class Program
{
    enum MenuSelection
    {
        CreateCustomer = 1,
        CreateAccount = 2,
        SetAccountBalance = 3,
        DisplayAccountBalance = 4,
        Exit = 5,
        MaxMenuSelection = 5,
    }

    public static void Main()
    {
        Enum
            .GetNames(typeof(MenuSelection))
            .Select(name => new 
            { 
                name, 
                index = (int)Enum.Parse(typeof(MenuSelection), name, true) 
            })
            .Select(kv => $"[{kv.index}] " + String.Join(" ", SplitByCamelCase(kv.name)))
            .Select(item => 
            {
                Console.WriteLine(item);
                return true;
            })
            .ToList();
    }

    public static bool IsLower(char ch) 
    {
        return ch >= 'a' && ch <= 'z';
    }

    public static string Head(string str)
    {
        return new String(
                    str
                        .Take(1)
                        .Concat(
                            str
                                .Skip(1)
                                .TakeWhile(IsLower)
                        )
                        .ToArray()
                );
    }

    public static string Tail(string str)
    {
        return new String(str.Skip(Head(str).Length).ToArray());
    }

    public static IEnumerable<string> SplitByCamelCase(string str) 
    {
        if (str.Length == 0) 
            return new List<string>();

        return 
            new List<string> 
            { 
                Head(str) 
            }
            .Concat(
                SplitByCamelCase(
                    Tail(str)
                )
            );
    }
}

结果:

[1] Create Customer
[2] Create Account
[3] Set Account Balance
[4] Display Account Balance
[5] Exit
[5] Max Menu Selection

See sample online

为什么不做点简单的,在单词之间加一个_?

那么你可以这样做:

    enum MenuSelection
    {
        Create_Customer = 1,
        Create_Account = 2,
        Set_Account_Balance = 3,
        Display_Account_Balance = 4,
        Exit = 5,
        MaxMenuSelection = 5,
    }
    public static void Menu()
    {
        for (int i = 1; i <= (int)MenuSelection.MaxMenuSelection; i++)
        {
            Console.WriteLine($"[{i}] {((MenuSelection)i).ToString().Replace("_"," ")}");
        }
    }

结果是:

 [1] Create Customer
 [2] Create Account
 [3] Set Account Balance
 [4] Display Account Balance
 [5] Exit

这是非常快速和肮脏的。但是,它的优点是您可以使用任何 enum 类型创建任何菜单。

它根据大小写 (upper/lower) 转换来分隔单词。它有效,除了你的 MaxMenuSelection。不要把它放在你的枚举中,而是让它成为一个模板(在枚举类型上)函数 return GetValues().Length(见下文):

下面显示的wherewhere T : struct,因为我使用的编译器不支持where T : System.Enum这样会好很多,但需要最新的编译器。

  public static string SeparateWords(string enumName)
  {
      var buffer = new StringBuilder();
      var wasLower = false;
      foreach (var c in enumName)
      {
          if (wasLower && char.IsUpper(c))
          {
              buffer.Append(' ');
          }

          buffer.Append(c);
          wasLower = char.IsLower(c);
      }

      return buffer.ToString();
  }

  public static void DisplayMenu<T>() where T : struct //should be System.Enum if possible
  {
      var enumType = typeof(T);
      var names = Enum.GetNames(enumType);
      var values = Enum.GetValues(enumType) as int[];
      for (var i = 0; i < names.Length; ++i)
      {
          Console.WriteLine($"[{values[i]}] {SeparateWords(names[i])}");
      }
  }

我得到这个输出:

[1] Create Customer
[2] Create Account
[3] Set Account Balance
[4] Display Account Balance
[5] Exit
[5] Max Menu Selection

当我调用这个时:

 EnumTest.DisplayMenu<MenuSelection>();

而且,您可以通过这样做获得 "Max Menu Selection":

public static int MaxMenuSelection<T>() where T : struct
{
    return Enum.GetValues(typeof(T)).Length;
}