需要在 C# 中创建大型 switch 语句的摘要

发布于 2024-08-08 23:07:53 字数 611 浏览 3 评论 0原文

好吧,我不知道如何解释它。但是我有一个 switch 语句,

string mystring = "hello";
switch(mystring)
{
case "hello":
break;
case "goodbye":
break;
case "example":
break;
}

当然这是一个例子,在实际情况下,每种情况都会发生不同的事情。 好的,希望您明白这一点,现在,由于不同案例的数量巨大,手动执行此操作是不可能的。我需要分别创建所有情况的列表,例如......对于上面的 switch 语句,我可能需要

string[] list = { "hello", "goodbye", "example" };

用 foreach 来完成一些我不知道的操作,任何帮助将不胜感激。

另外,提供的任何工作代码都很棒!

编辑: 人们要求了解更多细节,因此它的工作原理如下。 程序的用户输入一系列字符串。 根据他们输入的字符串,它会执行一些 if 和 else if 并基本上返回新字符串。我需要能够通过该程序创建所有可用选项的列表。我不能只列出一个列表并对其进行硬编码,因为我总是在语句中添加更多案例,而且我不能返回并保持列表最新。

Alright, i dont know how to explain it well.. but i have a switch statement,

string mystring = "hello";
switch(mystring)
{
case "hello":
break;
case "goodbye":
break;
case "example":
break;
}

of course this is an example, and in the real situation, there will be different things happening for each case.
ok, hope you get the point, now, doing this manually is impossible, because of the sheer number of different case's. i need to respectively create a list, of all the cases, so for instance.. for the above switch statement, i would need

string[] list = { "hello", "goodbye", "example" };

maybe could be done with a foreach some how i dont know, any help would be greatly appreciated.

also, any working codes provided would be awesome!

edit:
people are asking for more detail, so here is how it works.
the user of the program, inputs a series of strings.
based on the string(s) they entered, it will do a few if's and else if's and throw back the new strings basically. i need to be able to be able to create a list, through the program, of all the options available to use. and i cant just make a list and hard code it in, because im always adding more case's to the statement, and i cant be going back and keeping a list up to date.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

迷雾森÷林ヴ 2024-08-15 23:07:53

对于 VISUAL STUDIO:

如果 mystring 是枚举而不是字符串,则在 Visual Studio 中,如果您键入“switch”[TAB]“mystring”[ENTER],它将为您构建所有情况下的长开关。

FOR VISUAL STUDIO:

if mystring is an enum instead of a string, in visual studio, if you type "switch" [TAB] "mystring" [ENTER] it'll build the long switch for you with all the cases.

凝望流年 2024-08-15 23:07:53

这取决于您想要变得多么聪明...您可以创建一个自定义属性,该属性附加到带有该方法应处理的字符串的方法。然后,您只需找到具有所需值的属性并执行它,而不是使用 switch 语句。

using System;
using System.Reflection;

namespace ConsoleApplication1 {
    [AttributeUsage(AttributeTargets.Method)]
    internal class ProvidesAttribute : Attribute {
        private String[] _strings;
        public ProvidesAttribute(params String[] strings) {
            _strings = strings;
        }
        public bool Contains(String str) {
            foreach (String test in _strings) {
                if (test.Equals(str)) {
                    return true;
                }
            }
            return false;
        }
    }

    internal class Program {
        [Provides("hello", "goodbye")]
        public void HandleSomeStuff(String str) {
            Console.WriteLine("some stuff: {0}", str);
        }

        [Provides("this")]
        public void HandleMoreStuff(String str) {
            Console.WriteLine("more stuff: {0}", str);
        }

        public void HandleString(String str) {
            // we could loop through each Type in the assembly here instead of just looking at the
            // methods of Program; this would allow us to push our "providers" out to other classes
            MethodInfo[] methods = typeof(Program).GetMethods();
            foreach (MethodInfo method in methods) {
                Attribute attr = Attribute.GetCustomAttribute(method, typeof(ProvidesAttribute));
                ProvidesAttribute prov = attr as ProvidesAttribute;
                if ((prov != null) && (prov.Contains(str))) {
                    method.Invoke(this, new Object[] { str } );
                    break;  // removing this enables multiple "providers"
                }
            }
        }

        internal static void Main(String[] args) {
            Program prog = new Program();
            foreach (String str in args) {
                prog.HandleString(str);
            }
        }
    }
}

拥有框架后,您无需更改 HandleString() 代码,只需添加您想要处理的方法并为其设置 Provides 属性。如果您想进一步扩展这个想法,您可以创建多个类来处理各种字符串,然后循环遍历程序集中的每种类型以查找 Provides 属性。

编辑这还有一个额外的好处,即您可以定义作用于同一字符串的多个方法(通过删除循环逻辑中的break)。

It depends on how clever you want to get... You could create a custom attribute that attaches to a method with the string that method should handle. Then, instead of a switch statement, you would just find the attribute with your desired value and execute it.

using System;
using System.Reflection;

namespace ConsoleApplication1 {
    [AttributeUsage(AttributeTargets.Method)]
    internal class ProvidesAttribute : Attribute {
        private String[] _strings;
        public ProvidesAttribute(params String[] strings) {
            _strings = strings;
        }
        public bool Contains(String str) {
            foreach (String test in _strings) {
                if (test.Equals(str)) {
                    return true;
                }
            }
            return false;
        }
    }

    internal class Program {
        [Provides("hello", "goodbye")]
        public void HandleSomeStuff(String str) {
            Console.WriteLine("some stuff: {0}", str);
        }

        [Provides("this")]
        public void HandleMoreStuff(String str) {
            Console.WriteLine("more stuff: {0}", str);
        }

        public void HandleString(String str) {
            // we could loop through each Type in the assembly here instead of just looking at the
            // methods of Program; this would allow us to push our "providers" out to other classes
            MethodInfo[] methods = typeof(Program).GetMethods();
            foreach (MethodInfo method in methods) {
                Attribute attr = Attribute.GetCustomAttribute(method, typeof(ProvidesAttribute));
                ProvidesAttribute prov = attr as ProvidesAttribute;
                if ((prov != null) && (prov.Contains(str))) {
                    method.Invoke(this, new Object[] { str } );
                    break;  // removing this enables multiple "providers"
                }
            }
        }

        internal static void Main(String[] args) {
            Program prog = new Program();
            foreach (String str in args) {
                prog.HandleString(str);
            }
        }
    }
}

Once you have the framework, you wouldn't need to alter the HandleString() code, just add the methods you want to take care of and set the Provides attribute on them. If you wanted to extend the idea a little further, you could create multiple classes to handle a wide variety of strings, then loop through each type in your assembly looking for the Provides attribute.

EDIT this has the added benefit that you can define multiple methods that act on the same string (by removing the break in the loop logic).

生生不灭 2024-08-15 23:07:53

我确定你想做什么,但你也许可以使用字典。

    Dictionary<string, int> lookupTable = new Dictionary<string, int>();

    lookupTable.Add("hello", 1);
    lookupTable.Add("goodbye", 2);
    lookupTable.Add("example", 3);


    int output = lookupTable["hello"];

您不需要使用代码来添加每个单独的条目。您可以从文件中读取键和值,循环遍历它们并填充字典。

如果您详细解释您想要做什么,我们可以为您提供更具体的建议。

I'm note sure what you are trying to do, but you might be able to use a dictionary.

    Dictionary<string, int> lookupTable = new Dictionary<string, int>();

    lookupTable.Add("hello", 1);
    lookupTable.Add("goodbye", 2);
    lookupTable.Add("example", 3);


    int output = lookupTable["hello"];

You wouldn't need to have code to add each individual entry. You could read in the keys and values from a file, loop though them and populate the dictionary.

If you explain more about what you are trying to do, we could give you more specific advice.

墨离汐 2024-08-15 23:07:53

通过适当的重构(您的假设示例),您可以确保在您的大量案例中,有很多案例可以使用其字符串参数调用相同的子例程。

在许多这样的场景中,您甚至可能不需要一个巨大的 switch 语句,而只需参数化一个可以处理它们的子例程即可。

如果没有在案例陈述中具体说明您想要做什么,就很难得出具体的答案。

By proper refactoring (your hypothetical example) you can make sure that out of your sheer number of cases, there will be a lot of them that can call the same sub routine with their string parameter.

In many of these scenarios, you may not even need a huge switch statement, but just parameterize one sub routine that can handle them.

Without a concrete example of what you want to do in the case statements, it is hard to come up with a concrete answer.

伪装你 2024-08-15 23:07:53

您似乎正在尝试从代码中提取“命令字符串”,以便可以自动更新用户文档中的可用命令列表。我认为这不会给你带来太多好处,因为你仍然需要手动记录每个命令的作用。

话虽这么说,以下 powershell 命令将从 test.cs 中提取您想要的数据:

type test.cs|select-string 'case "(.*)"'|foreach {$_.Matches[0].Groups[1].Value}

You appear to be trying to extract "command strings" from your code, so that you can automatically update the list of available commands in your user documentation. I think this will not gain you much, as you will still need to manually document what each command does.

That being said, the following powershell command will extract the data you want from test.cs:

type test.cs|select-string 'case "(.*)"'|foreach {$_.Matches[0].Groups[1].Value}
维持三分热 2024-08-15 23:07:53

Switch 语句对常量进行计算,因此 case 语句不适用于变量。也许您应该考虑使用 Dictionary<>并在此基础上进行分支。但是,如果对您正在解决的问题没有更多的了解,那么说更多的话就没有什么意义。

Switch statements evaluate on constants, so the case statements won't work with variables. Perhaps you should consider using a Dictionary<> and branching based on that. But without any more insight into the problem you're solving, there's little point in saying anything more.

一个人的旅程 2024-08-15 23:07:53

创建一个抽象类,将其命名为StringHandler。给它2个抽象方法,1个检查处理程序是否可以处理该字符串,然后另一个进行处理。比如:

  public abstract class StringHandler
  {
    public abstract bool CanProcess(string input);
    public abstract void Process();
  }

  public class HelloStringHandler : StringHandler
  {
    public override bool CanProcess(string input)
    {
      return input.Equals("hello");
    }

    public override void Process()
    {
      Console.WriteLine("HELLO WORLD");
    }
  }

然后在你的主类中,你可以用所有已知处理程序的列表做一个简单的循环,就像

  List<StringHandler> handlers = new List<StringHandler>();
  handlers.Add(new HelloStringHandler());
  string myString = "hello";

  foreach (StringHandler handler in handlers)
  {
    if (handler.CanProcess(myString))
    {
      handler.Process();
      break;
    }
  }

所有这些都可以明显地优化/改进,但我希望你明白了?

Create an abstract class, call it something like StringHandler. Give it 2 abstract methods, 1 to check whether the handler can handle the string, then the other to do the processing. Something like:

  public abstract class StringHandler
  {
    public abstract bool CanProcess(string input);
    public abstract void Process();
  }

  public class HelloStringHandler : StringHandler
  {
    public override bool CanProcess(string input)
    {
      return input.Equals("hello");
    }

    public override void Process()
    {
      Console.WriteLine("HELLO WORLD");
    }
  }

Then in your main class you can do a simple loop with a list of all known handlers, like

  List<StringHandler> handlers = new List<StringHandler>();
  handlers.Add(new HelloStringHandler());
  string myString = "hello";

  foreach (StringHandler handler in handlers)
  {
    if (handler.CanProcess(myString))
    {
      handler.Process();
      break;
    }
  }

All this can be optimised/improved obviously, but I hope you get the picture?

嘿哥们儿 2024-08-15 23:07:53

我对 C# 很生疏,但这是一个有趣的小练习。下面的代码不是很干净,但会做你要求的事情。您将需要添加更多检查,更好地使用变量并添加更多逻辑,但这应该可以帮助您朝着正确的方向前进。

    var newfile = System.IO.File.CreateText("newcode.txt");
    newfile.Write("string[] list = { ");
    using (var file = System.IO.File.OpenText("code.txt"))
    {
        bool bFirst = true;
        while (!file.EndOfStream)
        {
            String line = file.ReadLine();

            if (line.Contains("case ") && line.EndsWith(":"))
            {
                line = line.Replace("case", " ");
                line = line.Replace(":", " ");
                line = line.Trim();
                if (bFirst == false)
                {
                    newfile.Write(", ");
                }
                bFirst = false;
                newfile.Write(line);
            }
        }
    }
    newfile.WriteLine(" };");
    newfile.Close();

祝你好运!

I am very rusty at c#, but this was a fun little exercise. The following code is not very clean, but will do what you asked. You will want to add more checks, use the variables better and add more logic, but this should help you get going in the right direction.

    var newfile = System.IO.File.CreateText("newcode.txt");
    newfile.Write("string[] list = { ");
    using (var file = System.IO.File.OpenText("code.txt"))
    {
        bool bFirst = true;
        while (!file.EndOfStream)
        {
            String line = file.ReadLine();

            if (line.Contains("case ") && line.EndsWith(":"))
            {
                line = line.Replace("case", " ");
                line = line.Replace(":", " ");
                line = line.Trim();
                if (bFirst == false)
                {
                    newfile.Write(", ");
                }
                bFirst = false;
                newfile.Write(line);
            }
        }
    }
    newfile.WriteLine(" };");
    newfile.Close();

Good luck!

羅雙樹 2024-08-15 23:07:53

受到@Jheddings 答案的启发,我想出了这个。也许它有点夸张,但至少我很高兴弄清楚它:

相对于 jheddings 解决方案的主要优点:

  • 使用扩展方法,不需要实用程序类实例。
  • 所有候选方法的反射查找仅在评估第一个字符串之前进行一次。之后就是简单的查找和调用了。
  • 使用更简单

    使用系统;
    使用 System.Collections.Generic;
    使用系统诊断;
    使用 System.Linq;
    使用系统反射;
    
    命名空间字符串切换器
    { 
    班级计划
    {
        静态无效主(字符串[]参数)
        {
            “noAction”。执行(); //没有动作,因为没有定义相应的方法
            “你好”。执行(); //调用Greet方法
            “世界”。执行(); //调用Shout方法
            “示例”.Execute(); //调用Shout方法
            Console.ReadKey();
        }
    
        //只处理一个关键字
        [关键词(“你好”)]
        静态公共无效问候(字符串s)
        {
            Console.WriteLine(s + "世界!");
        }
    
        //处理多个关键字
        [关键字(“世界”,“例子”)]
        静态公共无效喊(字符串s)
        {
            Console.WriteLine(s + "!!");
        }
    }
    
    内部静态类 ActionBrokerExtensions
    {
        静态字典<字符串,MethodInfo>行动;
    
        静态 ActionBrokerExtensions()
        {
            //在第一次调用 Execute() 时初始化查找机制
            actions = new Dictionary();
            //找出哪个类正在使用这个扩展
            类型 type = new StackTrace(2).GetFrame(0).GetMethod().DeclaringType;
            //获取具有正确属性和签名的所有方法
            var 方法 = type.GetMethods().Where(
            方法=> Attribute.GetCustomAttribute(method, typeof(KeywordsAttribute)) 是 keywordsAttribute &&
                      method.GetParameters().Length == 1 &&
                      method.GetParameters()[0].ParameterType.Equals(typeof(string)));
            //填充字典
            foreach(方法中的 var m)
            {
                var att = (Attribute.GetCustomAttribute(m, typeof(KeywordsAttribute)) as keywordsAttribute);
                foreach(att.Keywords 中的字符串 str)
                {
                    actions.Add(str, m);
                }
            }
        }
    
        public static void Execute(此字符串输入)
        {
            //调用通过关键字注册的方法 
            方法信息 mi;
            if (actions.TryGetValue(输入,输出 mi))
            {
                mi.Invoke(null, new[] { 输入 });
            }
        }
    }
    
    [AttributeUsage(AttributeTargets.Method)]
    内部类KeywordsAttribute:属性
    {
        私有 ICollection;关键词;
        公共关键字属性(参数字符串[]字符串)
        {
            keywords = new List<字符串>(字符串);
        }
    
        公共 ICollection;关键词
        {
            获取{返回关键字; }
        }
    }
    

    }

对任何奇怪的渲染表示歉意,由于某种原因,语法突出显示在代码中被阻塞:-(

Inspired by @Jheddings answer, I came up with this. Maybe it's over the top, but at least I had fun figuring it out:

Main benefits over jheddings solution:

  • Uses extension methods, no utility class instance needed.
  • Reflection lookup of all candidate methods is done only once, right before the first string is evaluated. Afterwards, it is a simple lookup and invoke.
  • Even simpler usage

    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Linq;
    using System.Reflection;
    
    namespace StringSwitcher
    { 
    class Program
    {
        static void Main(string[] args)
        {
            "noAction".Execute(); //No action, since no corresponding method defined
            "Hello".Execute();    //Calls Greet method
            "world".Execute();    //Calls Shout method
            "example".Execute();  //Calls Shout method
            Console.ReadKey();
        }
    
        //Handles only one keyword
        [Keywords("Hello")]
        static public void Greet(string s)
        {
            Console.WriteLine(s + " world!");
        }
    
        //Handles multiple keywords
        [Keywords("world", "example")]
        static public void Shout(string s)
        {
            Console.WriteLine(s + "!!");
        }
    }
    
    internal static class ActionBrokerExtensions
    {
        static Dictionary<string, MethodInfo> actions;
    
        static ActionBrokerExtensions()
        {
            //Initialize lookup mechanism once upon first Execute() call
            actions = new Dictionary<string, MethodInfo>();
            //Find out which class is using this extension
            Type type = new StackTrace(2).GetFrame(0).GetMethod().DeclaringType;
            //Get all methods with proper attribute and signature
            var methods = type.GetMethods().Where(
            method => Attribute.GetCustomAttribute(method, typeof(KeywordsAttribute)) is KeywordsAttribute &&
                      method.GetParameters().Length == 1 &&
                      method.GetParameters()[0].ParameterType.Equals(typeof(string)));
            //Fill the dictionary
            foreach (var m in methods)
            {
                var att = (Attribute.GetCustomAttribute(m, typeof(KeywordsAttribute)) as KeywordsAttribute);
                foreach (string str in att.Keywords)
                {
                    actions.Add(str, m);
                }
            }
        }
    
        public static void Execute(this string input)
        {
            //Invoke method registered with keyword 
            MethodInfo mi;
            if (actions.TryGetValue(input, out mi))
            {
                mi.Invoke(null, new[] { input });
            }
        }
    }
    
    [AttributeUsage(AttributeTargets.Method)]
    internal class KeywordsAttribute : Attribute
    {
        private ICollection<string> keywords;
        public KeywordsAttribute(params String[] strings)
        {
            keywords = new List<string>(strings);
        }
    
        public ICollection<string> Keywords
        {
            get { return keywords; }
        }
    }
    

    }

Apologies for any strange rendering, for some reason the syntax highlighting chokes on the code :-(

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文