1

わかりました、私はそれをうまく説明する方法がわかりません..しかし、私はスイッチステートメントを持っています、

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

もちろんこれは一例であり、実際の状況では、ケースごとに異なることが起こるでしょう。さて、これを手動で行うことは不可能です。さまざまなケースが非常に多いためです。すべてのケースのリストをそれぞれ作成する必要があるため、たとえば..上記のswitchステートメントの場合、必要になります

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

たぶん、私が知らない方法でforeachで行うことができます。どんな助けでも大歓迎です。

また、提供された作業コードは素晴らしいでしょう!

編集:人々はより詳細を求めているので、これがどのように機能するかです. プログラムのユーザーは、一連の文字列を入力します。入力した文字列に基づいて、いくつかの if と else if を実行し、基本的に新しい文字列を返します。プログラムを通じて、使用可能なすべてのオプションのリストを作成できるようにする必要があります。また、リストを作成してハードコードすることはできません。これは、常にステートメントにケースを追加するためであり、リストに戻って最新の状態に保つことはできません。

4

9 に答える 9

4

ビジュアル スタジオの場合:

mystring が文字列ではなく列挙型の場合、Visual Studio で "switch" [TAB] "mystring" [ENTER] と入力すると、すべてのケースで長いスイッチが作成されます。

于 2009-10-30T00:21:52.837 に答える
2

それはあなたがどれだけ賢くしたいかによって異なります...メソッドが処理する必要がある文字列を使用して、メソッドにアタッチするカスタム属性を作成できます。次に、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ループロジック内を削除することにより)。

于 2009-10-30T00:11:11.110 に答える
2

あなたが何をしようとしているのかは確かですが、辞書を使用できるかもしれません。

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

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


    int output = lookupTable["hello"];

個々のエントリを追加するためのコードは必要ありません。ファイルからキーと値を読み込み、それらをループして辞書に入力することができます。

何をしようとしているのかを詳しく説明していただければ、より具体的なアドバイスを差し上げることができます。

于 2009-10-30T00:20:27.803 に答える
1

ユーザー ドキュメントで使用可能なコマンドのリストを自動的に更新できるように、コードから「コマンド文字列」を抽出しようとしているようです。各コマンドの動作を手動で文書化する必要があるため、これはあまり役に立たないと思います。

そうは言っても、次のpowershellコマンドは、test.cs から必要なデータを抽出します

type test.cs|select-string 'case "(.*)"'|foreach {$_.Matches[0].Groups[1].Value}
于 2009-10-30T00:53:06.573 に答える
1

適切なリファクタリング (架空の例) により、膨大な数のケースから、文字列パラメーターで同じサブルーチンを呼び出すことができるケースが多数あることを確認できます。

これらのシナリオの多くでは、大規模な switch ステートメントさえ必要ないかもしれませんが、それらを処理できる 1 つのサブルーチンをパラメーター化するだけです。

caseステートメントで何をしたいのかの具体例がなければ、具体的な答えを思いつくのは難しい.

于 2009-10-30T00:19:31.440 に答える
0

私は 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();

幸運を!

于 2009-10-30T00:41:26.067 に答える
0

@Jheddingsの回答に触発されて、私はこれを思いつきました。たぶんそれはやり過ぎかもしれませんが、少なくとも私はそれを理解するのが楽しかったです:

jheddings ソリューションに対する主な利点:

  • 拡張メソッドを使用し、ユーティリティ クラス インスタンスは必要ありません。
  • すべての候補メソッドのリフレクション ルックアップは、最初の文字列が評価される直前に 1 回だけ実行されます。その後は、単純なルックアップと呼び出しです。
  • さらにシンプルな使い方

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

    }

奇妙なレンダリングについてお詫びします。何らかの理由で、構文の強調表示がコードでチョークします:-(

于 2009-10-30T02:29:06.317 に答える
0

抽象クラスを作成し、 のような名前を付けStringHandlerます。2 つの抽象メソッドを指定します。1 つはハンドラーが文字列を処理できるかどうかを確認するためのもので、もう 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;
    }
  }

これらはすべて明らかに最適化/改善できますが、全体像を理解していただければ幸いです。

于 2009-10-30T00:30:27.210 に答える
0

switch ステートメントは定数で評価されるため、case ステートメントは変数では機能しません。おそらく、 Dictionary<> を使用し、それに基づいて分岐することを検討する必要があります。しかし、解決しようとしている問題についての洞察がなければ、それ以上何を言っても意味がありません。

于 2009-10-30T00:21:11.860 に答える