Intro To Pattern Matching – Covers C# 9

栏目: IT技术 · 发布时间: 4年前

内容简介:Pattern matching is an essential and powerful building block to many functional programming languages like Haskell or Scala. Pattern matching allows the developer to match a value (or an object) against some patterns to select a branch/block of the code.I

What is Pattern Matching?

Pattern matching is an essential and powerful building block to many functional programming languages like Haskell or Scala. Pattern matching allows the developer to match a value (or an object) against some patterns to select a branch/block of the code.

I have used the Type Pattern to demonstrate the concept of the pattern matching,

inputData:  
1-  Does inputData match with a string?  
2-  Does inputData match with an int?  
3-  Or it is something else?    switch(inputData)  
switch(inputData)  
{  
  case string strBinded: {Execute the code}; 
  case int intBinded :{Execute the code};  
  case _ :  {Execute else code}  
}  

As you can see above, the type pattern can be used as a replacement for type check and type cast.

You can consider pattern matching as a replacement for if-else and the classic switch cases. But in the end, it is still another type of if-else.

Pattern Matching Core Concept

Intro To Pattern Matching – Covers C# 9

Figure -1- OOP example

Consider the following example,

public class Car  
{  
  private int fuel;  
  private int speed;  
   
  public Car(int fuel, int speed)  
  {  
    this.fuel = fuel;  
    this.speed = speed;  
  }  
   
  public void Deconstruct(out int fuel, out int speed)  
  {  
    fuel = this.fuel;  
    speed = this.speed;  
  }  
   
  public void SetFuel(int value)  
  {  
    this.fuel = value;  
  }  
   
  public int GetFuel()  
  {  
    return this.fuel;  
  }  
   
  public void SetSpeed(int value)  
  {  
    this.speed = value;  
  }  
   
  public int GetSpeed()  
  {  
    return this.speed;  
  }  
   
  public void Drive()  
  {  
    // Bohn Bohn brunn brunn  
    this.speed = this.speed + 10;  
    this.fuel = this.fuel - 5;  
  }  
}   
The object in the Object-Oriented Programming is encapsulated in one unit (the state and the behavior), the data structures, and the methods which work on those data structures. If you need new functionality, then we have to add a new method to the object definition. For example, you need to stop the car, then you have to add the Stop() {} to the class Car . If you want to add a few methods, then this approach is working fine. The problem comes when you want to add continually new methods all the time. You might realize that you have already written dozens of methods, and you have to add more methods like EngineOn(){}, Break(){}, and TurnLightOn(){} … etc. That can be quite a challenge to keep the code still maintainable. Pattern matching provides an alternative way to handle those problems.

The idea is simple.

Constructor

In the constructor, you pass the data structure (parameters) to collect and create the object.

public Car(int fuel, int speed)   

Deconstruct

Destructs an object to a tuple. It takes the data structures out of the object.

public void Deconstruct(out int fuel, out int speed)  
Intro To Pattern Matching – Covers C# 9

Figure -2- OOP vs. FP

As shown, in the image above, it becomes easy to perform the Car operations on the deconstructed data structures, and you can add the new operations(methods) easily. The core concept is, when you have a stable and a known data structure, it’s often very interesting to apply the pattern matching approach because you can quickly expand the operations. However, if your operations are stable, but the data changes, then the OOP approach seems more adequate.

Why is Pattern Matching so important in C#?

The first reason is that functional programming can be complementary to the OOP paradigm, and in recent history, we have seen many successful technologies based on the combination between OOP and FP like LINQ. The second reason is more political. C# is one of the top 10 languages. The world is changing very fast, and therefore, functional programming over time becomes more important than any other approach. The .Net development team could not tolerate the idea of losing their success; for this reason, they have decided to work aggressively in the innovation world. They are trying to expand everywhere, adding more new features and programming paradigms, and they are trying to make C# more performant and simplifying the syntax. I was not surprised when I saw the C# development team brings pattern matching and records to the center of the C# programming style. I suppose, with C# 10, we can do everything in a functional way. This aggressive development strategy is good and evil. One thing I have noticed in the last few years is that many C# developers are angry about that. Furthermore, the F# developers are very disappointed about including FP in C# and not empowering F#.

At this moment, F# evangelism and F# prophets became hopeless, and they are trying to compare the language syntaxes, and they are assuming that F# concepts deserve better.

Recap

C# 7.x

  • Constant patterns
  • Type patterns
  • Var patterns
  • Destruction
  • Pattern matching on generic type parameters

C# 8

  • Pattern matching enhancements:
  • Switch expressions
  • Property patterns
  • Tuple patterns
  • Positional patterns

C# 9 probably

  • Type patterns
  • Parenthesized patterns
  • Relational patterns
  • Combinator Patterns
    • Conjunctive and patterns that require both of two different patterns to match.
    • Disjunctive or patterns that require either of two different patterns to match.
    • Negated not patterns that require a given pattern not to match.

I recommend you to read my old article about Pattern Matching,

https://www.infoq.com/articles/cs8-ranges-and-recursive-patterns/

!!IMPORTANT!!

The plan and the C# 9 proposals, still in the draft stage, have not yet been put into the final form for a decision by the .Net development team. The syntax might be changed, or the below proposal might be removed from the C# 9 milestone. 

C# 9 Pattern Matching

The .NET development team is considering a small handful of enhancements to pattern matching for C# 9.0 that have a natural synergy and work well to address several common programming problems,

  • Type patterns  is used to match the input against a type. If the input type is a match to the type specified in the pattern, the match succeeds.
  • Parenthesized patterns  permit the programmer to put parentheses around any pattern.
  • Relational patterns  permits the programmer to express that an input value must satisfy a relational constraint when compared to a constant value.
  • Combinator Patterns  permits the programmer to combine multiple patterns on one line, with AND/OR operators, or to negate a pattern by using the NOT operator,
    • Conjunctive and patterns that require both of two different patterns to match.
    • Disjunctive or patterns that require either of two different patterns to match.
    • Negated not patterns that require a given pattern not to match. 

Type Patterns

In C# 7, we have seen that the is-type operator extends to be an is expression. C# 9 introduces a new type pattern, which can also be used to match the input against a type. This pattern is nothing more than a minor syntactic convenience.

Example

nt age = 42;  
string name= "Bassam";  
var userTuple = (age, name);  
  
// Current version  
// test if age is an int and name is a string  
if (userTuple is (int _, string _) )   
{  
  Console.WriteLine(userTuple.name);  
}  
  
// C# 9  
// test if age is an int and name is a string  
if (userTuple is (int, string) )   
{  
  Console.WriteLine(userTuple.name);  
}  

Compare the C# Syntax trees,

Current C# version,

Intro To Pattern Matching – Covers C# 9

Figure -3- Syntax tree for: if (userTuple is (int _, string _) )

C# 9

Intro To Pattern Matching – Covers C# 9

Figure -4- Syntax tree for: if (userTuple is (int, string) )

Comparing the IL Code for Pattern Matching

Produced IL Code

// int age = 42;  
IL_0000: ldc.i4.s 42  
IL_0002: stloc.0  
  
// string name= "Bassam";  
IL_0003: ldstr "Bassam"  
IL_0008: stloc.1  
  
// var userTuple = (age, name);  
IL_0009: ldloca.s 2  
IL_000b: ldloc.0  
IL_000c: ldloc.1  
IL_000d: call instance void valuetype [System.Private.CoreLib]System.ValueTuple`2<int32, string>::.ctor(!0, !1)  
  
// if (userTuple is (int _, string _) ) // Current Version  
IL_0012: ldloc.2  
IL_0013: ldfld !1 valuetype [System.Private.CoreLib]System.ValueTuple`2<int32, string>::Item2  
IL_0018: brfalse.s IL_0025  
  
// System.Console.WriteLine(userTuple.name);  
IL_001a: ldloc.2  
IL_001b: ldfld !1 valuetype [System.Private.CoreLib]System.ValueTuple`2<int32, string>::Item2  
IL_0020: call void [System.Console]System.Console::WriteLine(string)   
  
// if (userTuple is (int, string) ) // C# 9  
IL_0025: ldloc.2  
IL_0026: ldfld !1 valuetype [System.Private.CoreLib]System.ValueTuple`2<int32, string>::Item2  
IL_002b: brfalse.s IL_0038  
  
// System.Console.WriteLine(userTuple.name);  
IL_002d: ldloc.2  
IL_002e: ldfld !1 valuetype [System.Private.CoreLib]System.ValueTuple`2<int32, string>::Item2  
IL_0033: call void [System.Console]System.Console::WriteLine(string)

Pattern Combinators

Permits matching both of two different patterns using and/or operators or the negation of a pattern by using not operator.

Pattern Combinators consist of the following sub-patterns,

  • Conjunctive and patterns that require both of two different patterns to match.
  • Disjunctive or patterns that require either of two different patterns to match.
  • Negated not patterns that require a given pattern not to match. 

AND “Conjunctive” Pattern

Permits the AND Logics on two different patterns.

Example

if (o is int and 1) { } // The code block will be executed if the o is of type int and its value is 1  

OR “Disjunctive” Pattern

Permits the OR Logics on two different patterns.

Example

if (o is (1 or 2) and int x4) { } // The code block will executed if the value of o is 1 or 2   

Negated Pattern

Permits the NOT Logics on a pattern.

Example

if (e is not null) { }  
The code will be executed when e is a reference type and not null. I love It! And I hope the keyword not will not replace with the ugly operator ~.

Neal Gafter example:

The and or combinators will be useful for testing ranges of values. 

bool IsLetter(char c) => c is >= 'a' and <= 'z' or >= 'A' and <= 'Z';  

Examples

if (o is int x1 and 1) { }  
if (o is int x2 and (1 or 2)) { }   

The code block will be executed if the o is of type int, then (copy o to x2), and x2 value must be 1 or 2. As we can see above, we have also used Parenthesized patterns. Unfortunately, the Range Pattern is declined; in other words, you cannot do in C# 9:     The alternative for that is Relational Patterns, which is described in the

section below. 

if (o is 1 and int x3) { }  
if (o is not (1 or 2) and int x5) { }  

Parenthesized patterns

According to the documents, the Parenthesized patterns can be grouped around patterns to achieve the desired associativity. In the following example, parentheses are used to control associativity between AND pattern and Or pattern.

Back to the Neal Gafter example:

The and and or combinators will be useful for testing ranges of values.

bool IsLetter(char c) => c is >= 'a' and <= 'z' or >= 'A' and <= 'Z'; // and & or combinators  

The below example illustrates that the and-operator will have a higher parsing priority (i.e. will bind more closely) than the or-opreator . The programmers can use the parenthesized pattern to make the precedence explicit:

bool IsLetter(char c) => c is (>= 'a' and <= 'z') or (>= 'A' and <= 'Z');  

Relational patterns

Allows the case-labels in switch-statement to support the comparison operators, much like the Select Case statement in Visual Basic.

Supported operators and types

==, !=, <, <=, >, and >= on all of the built-in types that support such binary relational operators with two operands of the same type in an expression. Specifically, it supports all of these relational patterns for sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, and decimal. Additionally, it supports == and != for string and bool.

Back to Neal Gafter Examples: 

bool IsHexLetter(char c) => c is in 'A' to 'Z' or in 'a' to 'z';  
The 'to' keyword would be used to specify a range. In this case [A..Z] or [a..z].

Switch-label

So, you could write code as in this example:

int iq = DoIqTest();  
   
switch (iq)  
{  
    case <= 69:  
        ProcedureExtremelyLow();  
        break;  
    case 70 to 79:  
        BorderlineProcedure();  
        break;  
    case 80 to 89:  
        LowAverageProcedure();  
        break;  
    case 90 to 99:  
    case 101 to 109:  
        AverageProcedure();  
        break;  
    case 100:  
        ExactlyMedianProcedure();  
        break;  
    case 110 to 119:  
        HighAverageProcedure();  
        break;  
    case 120 to 129:  
         SuperiorProcedure();  
         break;  
    case >= 130:  
        VerySuperiorProcedure();  
        break;  
}  
The to keyword would be used to specify a range. In the statement switch (value), case x to y: would be equivalent to the boolean expression value >= x && value <= y .

Summary

The term pattern matching is a central feature of functional programming languages. This approach can be used to solve many programming problems efficiently. C# 9 and 10 will support the most F# Pattern Matching concepts.


以上所述就是小编给大家介绍的《Intro To Pattern Matching – Covers C# 9》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

跨境电商——阿里巴巴速卖通宝典

跨境电商——阿里巴巴速卖通宝典

速卖通大学 编著 / 电子工业出版社 / 2015-1 / 69.00元

跨境电商作为中国电子商务发展的最新趋势,受到了全社会越来越多的重视,大量中国卖家借助阿里巴巴速卖通平台,将产品直接售卖到全球的消费者手中,通过这条短得不能再短的交易链,获得了丰厚的回报。 但同时,跨境电商这一贸易形式,对卖家的综合素质要求比较高:卖家要对海外市场比较熟悉,对跨境物流有所把握,能够用外语进行产品介绍和客户交流,通过跨境结算拿到货款……诸如此类的门槛,让不少新卖家心生畏难,而所有......一起来看看 《跨境电商——阿里巴巴速卖通宝典》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码