2016-03-24 33 views
2

目前我正在C#中完成一個大學項目,其中包括將一種形式的代碼轉換爲另一種形式的代碼,其中涉及從許多可用的方法中選擇適當的方法/函數。這裏的問題是,使用任何模式匹配技術來實現這一點,而不是使用許多IF ELSE語句。在C#中使用模式匹配選擇合適的方法

現在我已經完成了這個使用嵌套的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#,我不知道這樣的事情是否存在(谷歌搜索,但沒有找到我在找什麼),所以任何關於這個問題的幫助將是非常有用的(使用)進一步的發展。

很多預先感謝。

+0

你能告訴我們你得到的實際代碼嗎? Type3(var data)函數''是無效的C#。我很難通過'get(3 int)'來表達你的意思。你在說重載嗎? – Rob

+0

'dynamic'關鍵字作爲返回類型允許您返回任意值。然後你可以檢查你使用'typeof'操作符返回的類型,也許可以嘗試挖掘該材料並查看是否可以在你的案例中使用它。 ('public dynamic ProcessGET()'然後可以毫無問題地返回'Type1','Type2'和'Type3'對象。) –

+0

@Rob - 那些get()輸入方法是我自己定製的語法。 – Unknown

回答

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語句。每個匹配器都有自己的小類,您可以爲每個匹配器編寫單元測試。此外,使用正則表達式使您的匹配器更簡單。

+0

是的,這減少了。將嘗試使用這個概念。謝謝你的回答。 – Unknown

0

我會在這裏留下一些建議,以供您查看。這是一些基本的代碼。

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 string(在操作者is如果). It could have also been done with(firstOutput.GetType()== typeof運算(字符串))`。

第二種方法將是一個經典的「解析和流延」技術。我們解析格式<type>:<value>的輸入字符串,然後調用與轉換或解析參數不同的功能。這也許是你想要的。

還有給一個任意函數的類型。在那裏,你可以在dynamic上輸入參數的關鍵字是「哈克」的方式,如在

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

「oldschool」方法(不使用dynamic)將僅將object類型傳遞給每個函數,但解析是等效的(if(someArgument.GetType() == typeof(string)) ...)。

希望這給你一些關於如何解析這些字符串的想法,將它們轉換爲不同的類型並用它調用不同的函數。

+0

感謝您提供大量有用的附加信息。將弄清楚,如果我能夠使用這些動態類型 – Unknown

0

所以這些類型被存儲爲一個列表中的字符串,對吧?你想根據字符串的值調用一個不同的函數?

下面我將如何完成你的代碼:

  1. 創建一個接口:

    public interface IMyType 
         { 
          string Result(); 
          string Input {get; set;} 
    
         } 
    
  2. 和其中三個實現它的類:

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

    (對於Type2和Type3重複)

3.then創建返回基於模式這三種 符合字符串輸入

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

      } 
    } 

也許值得看的正則表達式的字符串匹配太

+0

感謝您的解決方案。我認爲,與直接使用「IF ELSE」語句相比,這種方法絕不會減少「IF」語句的使用數量,但它有助於隱藏大量的「IF」語句。 ProcessGET()方法的foreach(...)循環內部的3個條件檢查語句(IF,IF ELSE,ELSE)被移至獨立的方法,並執行相同的操作。但是,正如我所說,它有助於隱藏/分離這些條件語句。 – Unknown