необходимо создать сводку большого оператора switch в C # - PullRequest
1 голос
/ 30 октября 2009

Хорошо, я не знаю, как это объяснить хорошо ... но у меня есть оператор switch,

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

конечно, это пример, и в реальной ситуации в каждом случае будут происходить разные вещи. Хорошо, надеюсь, вы поняли, что делать это вручную невозможно из-за большого количества разных случаев. мне нужно, соответственно, создать список всех случаев, например, для приведенного выше оператора switch, мне нужно будет

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

Может быть, можно было бы сделать с foreach некоторые, как я не знаю, любая помощь будет принята с благодарностью.

также, любые предоставленные рабочие коды будут великолепны!

редактирование: люди просят более подробно, вот как это работает. Пользователь программы вводит последовательность строк. основываясь на введенной ими строке (строках), он выполнит несколько «если» и «еще», если вернет новые строки. Мне нужно, чтобы я мог создавать список всех доступных вариантов использования через программу. и я не могу просто составить список и жестко запрограммировать его, потому что я всегда добавляю больше операторов в оператор, и я не могу вернуться и поддерживать список в актуальном состоянии.

Ответы [ 9 ]

4 голосов
/ 30 октября 2009

ДЛЯ ВИЗУАЛЬНОЙ СТУДИИ:

если mystring - это enum вместо строки, в Visual Studio, если вы введете «switch» [TAB] «mystring» [ENTER], он создаст для вас длинный ключ во всех случаях.

2 голосов
/ 30 октября 2009

Я точно знаю, что вы пытаетесь сделать, но вы можете использовать словарь.

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

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


    int output = lookupTable["hello"];

Вам не нужно иметь код для добавления каждой отдельной записи. Вы можете читать ключи и значения из файла, проходить через них и заполнять словарь.

Если вы объясните больше о том, что вы пытаетесь сделать, мы могли бы дать вам более конкретный совет.

2 голосов
/ 30 октября 2009

Это зависит от того, насколько умным вы хотите получить ... Вы можете создать собственный атрибут, который присоединяется к методу со строкой, которую этот метод должен обработать. Затем вместо оператора 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 в логике цикла).

1 голос
/ 30 октября 2009

Вы, кажется, пытаетесь извлечь «строки команд» из своего кода, чтобы вы могли автоматически обновлять список доступных команд в вашей пользовательской документации. Я думаю, что это не принесет вам большой пользы, поскольку вам все равно придется вручную задокументировать, что делает каждая команда.

При этом следующая команда powershell извлечет нужные данные из test.cs:

type test.cs|select-string 'case "(.*)"'|foreach {$_.Matches[0].Groups[1].Value}
1 голос
/ 30 октября 2009

Путем правильного рефакторинга (ваш гипотетический пример) вы можете быть уверены, что из вашего огромного числа случаев будет много из них, которые могут вызывать одну и ту же подпрограмму со своим строковым параметром.

Во многих из этих сценариев вам может даже не потребоваться огромный оператор switch, а просто параметризовать одну подпрограмму, которая может их обработать.

Без конкретного примера того, что вы хотите сделать в кейсах, сложно найти конкретный ответ.

0 голосов
/ 30 октября 2009

Вдохновленный ответом @Jheddings, я придумал это. Может быть, это слишком, но, по крайней мере, мне было интересно понять это:

Основные преимущества по сравнению с решением Jheddings:

  • Используются методы расширения, экземпляр вспомогательного класса не требуется.
  • Поиск в отражении всех возможных методов выполняется только один раз, непосредственно перед оценкой первой строки. После этого это простой поиск и вызов.
  • Еще более простое использование

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

    }

Извиняюсь за любой странный рендеринг, по какой-то причине подсветка синтаксиса блокирует код: - (

0 голосов
/ 30 октября 2009

Я очень ржавый на 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();

Удачи!

0 голосов
/ 30 октября 2009

Создайте абстрактный класс, назовите его как 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;
    }
  }

Очевидно, что все это можно оптимизировать / улучшить, но я надеюсь, что вы получите картину?

0 голосов
/ 30 октября 2009

Операторы Switch оценивают константы, поэтому операторы case не будут работать с переменными. Возможно, вам следует рассмотреть возможность использования словаря <> и ветвления на его основе. Но без более глубокого понимания проблемы, которую вы решаете, бессмысленно говорить что-либо еще.

...