在C#

时间:2016-03-24 14:24:58

标签: c# asp.net .net pattern-matching

目前正在C#中进行大学项目,其中包括将一种代码形式转换为另一种形式的代码,其中涉及从许多可用方法中选择适当的方法/功能。这里的问题是,使用任何模式匹配技术实现它,而不是使用许多IF ELSE语句。

目前我已经使用嵌套的IF ELSE语句实现了这一点,这些语句填充整个程序,并在完成时看起来像幼稚的代码。

当前实施: -

输入:

//stored in list<string>
get(3 int)      //type1
get(int:a,b,c)  //type2
get(name)       //type3
//list passed to ProcessGET method

使用if else:

public string ProcessGET(List<string> inputData)
{
      foreach(var item in inputData)
      { 
         if (inputData.item.Split('(')[1].Split(')')[0].Contains(':'))
         {
            return Type2 result;
         }
         else if (!inputData.item.Split('(')[1].Split(')')[0].Contains(':') && Convert.ToInt32(inputData.item.Split('(')[1].Split(')')[0].Split(' ')[0])>0)
         {
            return Type1 result;
         }
         else
         {
            return Type3 result;
         }
      }   
}

我想要的是这样的,

/stored in list<string>
get(3 int)      //type1
get(int:a,b,c)  //type2
get(name)       //type3
//list passed to ProcessGET method


public string ProcessGET(List<string> inputData)
{
      foreach(var itm in inputData)
      { 
        // call appropriate method(itm) based on type using some pattern matching techniques
      }   
}

string Method1(var data)
{
    return result for type1;  
}   
string Method2(var data)
{
    return result for type2;  
}
string Method3(var data)
{
    return result for type3;  
}

通常我的程序主要为各种类型的输入关键字做这种工作,比如'get','output','declare'等等......其中Get转换为Scanf语句,输出到printf语句等等上。 在这种情况下,如果我使用IF ELSE,我的项目充满了If else语句。

当我刚开始学习C#时,我不知道这样的事情是否存在(谷歌搜索但是没有找到我想要的东西),所以关于这个问题的任何帮助都将非常有帮助(使用)发展。

非常感谢提前。

3 个答案:

答案 0 :(得分:3)

解决此问题的另一种方法是引入一个界面,比如IMatcher。该接口有一个方法Match,它返回您的类型或完全转换的行。

您创建了多个实现IMatcher的类。

然后您的主循环变为:

var matchers = new [] { new MatcherA(), new MatcherB(), ... };

foreach (string line in input)
  foreach (matcher in matchers)
  {
     var match = matcher.Match(line);
     if (match != null) return match;
  }

没有更大的if声明。每个匹配器都有自己的小类,您可以为每个匹配器编写单元测试。此外,使用RegEx可以使您的匹配器更简单。

答案 1 :(得分:1)

我会在这里留下一些你可以看一下的建议。这是一些基本代码。

using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;

namespace TestStuff
{
    class Program
    {
        //Input string should be of the form "<type>:<index>"
        static dynamic GiveMeSomethingDynamic(string someInput)
        {
            /* predefined arrays sothat we can return something */
            string[] _storedStrings = { "Word 1", "word 2", "word 3" };
            int[] _storedInts = { 1, 2, 3 };
            float[] _storedFloats = { 3.14f, 2.71f, 42.123f };

            /* Parse the input command (stringly typed functions are bad, I know.) */
            string[] splitted = someInput.Split(':');
            string wantedType = splitted[0];
            int index = int.Parse(splitted[1]);

            /* Decide what to return base on that argument */
            switch (wantedType)
            {
                case "int":
                    return _storedInts[index];
                case "string":
                    return _storedStrings[index];
                case "float":
                    return _storedFloats[index];

                //Nothing matched? return null
                default:
                    return null;
            }
        }

        static void Main(string[] args)
        {
            /* get some return values */
            dynamic firstOutput = GiveMeSomethingDynamic("string:0");
            dynamic secondOutput = GiveMeSomethingDynamic("int:1");
            dynamic thirdOutput = GiveMeSomethingDynamic("float:2");

            /* Display the returned objects and their type using reflection */
            Console.WriteLine("Displaying returned objects.\n" +
                              "Object 1: {0}\t(Type: {1})\n" +
                              "Object 2: {2}\t\t(Type: {3})\n" +
                              "Object 3: {4}\t\t(Type: {5})\n",
                              firstOutput, firstOutput.GetType(),
                              secondOutput, secondOutput.GetType(),
                              thirdOutput, thirdOutput.GetType());

            /* Act on the type of a object. This works for *all* C# objects, not just dynamic ones. */
            if (firstOutput is string)
            {
                //This was a string! Give it to a method which needs a string
                var firstOutputString = firstOutput as string; //Cast it. the "as" casting returns null if it couldn't be casted.
                Console.WriteLine("Detected string output.");
                Console.WriteLine(firstOutputString.Substring(0, 4));
            }

            //Another test with reflection. 
            Console.WriteLine();

            //The list of objects we want to do something with
            string[] values = { "string:abcdef", "int:12", "float:3.14" };
            foreach(var value in values)
            {
                /* Parse the type */
                string[] parsed = value.Split(':');
                string _type = parsed[0];
                string _argument = parsed[1];

                switch (_type)
                {
                    case "string":
                        //This is a string.
                        string _stringArgument = _argument as string;
                        Method1(_stringArgument);
                        break;
                    case "int":
                        //Do something with this int
                        int _intArgument = int.Parse(_argument);
                        Method2(_intArgument);
                        break;
                    case "float":
                        float _floatArgument = float.Parse(_argument);
                        Method3(_floatArgument);
                        break;

                    default:
                        Console.WriteLine("Unrecognized value type \"{0}\"!", _type);
                        break;
                }

            }


            Console.ReadLine();
        }

        public static void Method1(string s) => Console.WriteLine("String Function called with argument \"{0}\"", s);
        public static void Method2(int i) => Console.WriteLine("int Function called with argument {0}", i);
        public static void Method3(float f) => Console.WriteLine("float Function called with argument {0}", f);
    }
}

函数GiveMeSomethingDynamic()给出的第一种方法依赖于dynamic关键字,它可以返回任意类型。根据输入字符串,它可以返回stringintfloat。在Main()函数中调用该方法,并且例如使用例如方法检查返回对象的类型。 firstOutput is stringis运算符). It could have also been done with if(firstOutput.GetType()== typeof(string))`。

第二种方法是经典的“解析和演员”技巧。我们解析格式为<type>:<value>的输入字符串,然后使用转换或解析的参数调用不同的函数。这可能是你想要的。

还有一种“hacky”方式赋予函数任意类型。在那里,您可以在输入参数上使用dynamic关键字,如

 public dynamic superDynamic(dynamic inputVar) 
 {
    //Figure out the type of that object
    //return something dynamic
 } 

“oldschool”方法(不使用dynamic)只会将object类型传递给每个函数,但解析是等效的(if(someArgument.GetType() == typeof(string)) ...)。

希望这能为您提供一些关于如何解析这些字符串,将它们转换为不同类型并使用它调用不同函数的想法。

答案 2 :(得分:1)

所以类型作为字符串存储在列表中,对吧?你想根据字符串的值调用不同的函数吗?

以下是我完成代码的方式:

  1. 创建界面:

    public interface IMyType 
            {
                string Result(); 
                string Input {get; set;}
    
            }
    
    1. 以及实现它的三个类:

       public class Type1 : IMyType
          {
              public string Result()
              {
                  // do something
              }
              public string Input {get; set;}
      
      
          }
      

      (重复Type2和Type3)

  2. 3.然后创建一个返回这三种类型之一的方法 基于匹配字符串输入的模式

        public IMyType GetAppropriateType(string input)
        { 
        if (inputData.item.Split('(')[1].Split(')')[0].Contains(':'))
                 {
                    return new Type2 {Input = input};
                 }
        //etc
        }
    
        public string ProcessGET(List<string> inputData)
        {
              foreach(var itm in inputData)
              { 
                 IMyType type = GetAppropriateType(itm);
                 type.Result();
    
              }   
        }
    

    也可能值得查看字符串匹配的正则表达式