2017-05-07 35 views
5

Piszę prosty tokenizer matematyczny i próbuję użyć nowej funkcji C# pattern matching.Przypadek pasujący do wzoru, gdy

Tokenizer jest dość prosta:

public IEnumerable<IToken> Tokenize(string input) 
    { 
     const char decimalSeparator = '.'; 
     string inputWithoutSpaces = input.Replace(" ", string.Empty); 
     var numberBuffer = new StringBuilder(); 
     var letterBuffer = new StringBuilder(); 
     foreach (char c in inputWithoutSpaces) 
     { 
      switch (c) 
      { 
       case var _ when IsTerm(c, letterBuffer): 
        if (numberBuffer.Length > 0) 
        { 
         yield return EmptyNumberBufferAsLiteral(numberBuffer); 
         yield return new Operator('*'); 
        } 
        letterBuffer.Append(c); 
        break; 
       case decimalSeparator: 
       case var _ when IsDigit(c): 
        numberBuffer.Append(c); 
        break; 
       case var _ when IsOperator(c): 
        if (numberBuffer.Length > 0) 
        { 
         yield return EmptyNumberBufferAsLiteral(numberBuffer); 
        } 
        if (letterBuffer.Length > 0) 
        { 
         yield return EmptyLetterBufferAsTerm(letterBuffer); 
        } 
        yield return new Operator(c); 
        break; 
      } 
     } 
     if (numberBuffer.Length > 0) 
     { 
      yield return EmptyNumberBufferAsLiteral(numberBuffer); 
     } 
     if (letterBuffer.Length > 0) 
     { 
      yield return EmptyLetterBufferAsTerm(letterBuffer); 
     } 
    } 

Używam case var _ ponieważ chcę, aby dopasować według stanu bez użycia if-else if łańcuch, ale jestem w stanie napisać case when bez określania var variableName.

Czy istnieje jakiś sposób na wykonanie takiej operacji? Czy jest to zalecany sposób na robienie tych rzeczy?

+1

Cóż, nadużywasz porównywania wzorców, aby ominąć wymóg używania stałych w instrukcjach przełączania, więc nie ma sposobu na obejście tego. Dodatkowo, myślę, że twoja logika prawdopodobnie pasuje/czyta lepiej, tak czy inaczej, tak czy inaczej. – DavidG

+1

@DavidG wręcz przeciwnie, wygląda to na Active Patterns, co znacznie ułatwia implementację tokenizerów i parserów. Dopasowanie do wzorca w C# 7 pomija kilka ważnych cech. Aktywne wzorce są jednym z nich. Zyskałbym wyższy priorytet, jeśli chodzi o wyczerpujące dopasowywanie, ale –

+0

@PanagiotisKanavos Tak, ale mówię o tym, co jest teraz dostępne w tym języku. Jestem prawie pewien, że zobaczymy dużo więcej elementów dopasowujących do wzorca, które pojawią się w C# w przyszłości (głównie dzięki F #, które zakładam). – DavidG

Odpowiedz

2

Istnieje "fantazyjny" sposób na porównywanie wzorców w ten sposób, przy użyciu tak zwanych aktywnych wzorów. C# nie obsługuje (jeszcze) aktywnych wzorów, ale see this answer for an example of what they might look like if/when implemented.

Więc za pomocą aktywnych wzorów, Twój kod będzie w końcu wygląda mniej więcej tak:

switch (c) 
{ 
    case Term(letterBuffer): 
     ... 
     break; 
    case decimalSeparator: 
    case Digit(): 
     ... 
     break; 
    case Operator(): 
     ... 
     break; 
} 

Jeśli chcesz, aby zobaczyć tę funkcję w przyszłej wersji C#, please upvote it on the csharplang github repo.

W międzyczasie ograniczasz się do wyboru między trzymaniem się stwierdzeń if, jak mówili inni, lub używaniem, gdy jesteście strażnikami. To, na co tak naprawdę idziesz, to tylko kwestia preferowanego stylu.

+0

Wolałbym, aby najpierw wprowadzono pełne dopasowywanie, aby zapobiec "nieodebranym" przypadkom. –

+1

@PanagiotisKanavos zgadzam się całkowicie. Niestety, myślę, że zobaczymy odpowiednie dopasowanie wzorca popychane na korzyść wielu innych funkcji związanych z OO. Tak więc pseudo-aktywne wzorce Op będą działały przez jakiś czas. –

Powiązane problemy