C# 7.0 新特性:模式匹配 ( pattern matching)


C# 7.0 新特性:模式匹配 ( pattern matching )

在 C# 中,is 是一個關鍵字,可以用來檢查某個數據的類型是否為特定類型。這是一個表達式,返回類型為 boolean。

例如,我們可以檢查某個實例是否為 Persion 類型

if (obj is Person) {
   // Do something if obj is a Person.
}

 

在下面情況下,返回 true:

  • 表達式的類型與 is 類型相符
  • 表達式的類型為 is 類型的派生類型
  • 表達式具有一個編譯時類型, 它是 is 類型的基類,在運行時的值為 is 類型的派生類型
  • 表達式實現了 is 類型的接口

支持模式匹配的 is

類型模式

在 C# 7.0 中,is 在原來的基礎上,額外提供了類型轉換的支持。可以在類型檢查的基礎上,直接支持類型轉換。

在下面的示例中,我們希望檢查對象的類型,如果為指定類型,我們要轉型為特定的類型進行操作。

using System;

public class Example
{
   public static void Main()
   {
      Object o = new Person("Jane");
      ShowValue(o);
      
      o = new Dog("Alaskan Malamute");
      ShowValue(o);
   }

   public static void ShowValue(object o)
   {
      if (o is Person p) {
         Console.WriteLine(p.Name);
      }   
      else if (o is Dog d) {
         Console.WriteLine(d.Breed);
      }             
   }
}

public struct Person
{  
   public string Name { get; set; }
   
   public Person(string name) : this()
   {
      Name = name;
   }
}

public struct Dog
{
   public string Breed { get; set; }

   public Dog(string breedName) : this()
   {
      Breed = breedName;
   }
}
// The example displays the following output:
//    Jane
//    Alaskan Malamute

 

等價的以前代碼為:

if (o is Person) { Person p = (Person) o;
         Console.WriteLine(p.Name);
}   
else if (o is Dog) { Dog d = (Dog) o;
         Console.WriteLine(d.Breed);
}

 

常量匹配

is 后面還可以是常量,is 測試表達式的值是否為特定常量。在以前版本中,這需要使用 switch 來支持。

using System;

public class Dice
{
    Random rnd = new Random();
    public Dice()
    {

    }
    public int Roll()
    {
        return rnd.Next(1, 7); 
    }
}

class Program
{
    static void Main(string[] args)
    {
        var d1 = new Dice();
        ShowValue(d1);
    }

    private static void ShowValue(object o)
    {
        const int HIGH_ROLL = 6;

        if (o is Dice d && d.Roll() is HIGH_ROLL)
            Console.WriteLine($"The value is {HIGH_ROLL}!");
        else
            Console.WriteLine($"The dice roll is not a {HIGH_ROLL}!");
     }
}
// The example displays output like the following:
//      The value is 6!

 

var 匹配

如果 is 后面是 var,則永遠為 true 。並把值賦予后面的變量。

例如,下面代碼將 item 賦予了 obj。

if (item is var obj)

 

需要注意的是,即使被測試的值為 null,is 表達式還是為 true。此時,變量將被賦予 null。

 

支持模式匹配的 Switch

所有的 c# 版本都支持常量模式,在 C#  7.0 中,現在支持類型模式了。也就是說,在 case 后面還可以是一個用來檢測的類型。

case type varname

相當於在這里使用了 is 。

從 C# 7.0 開始,您還可以在上面的表達式后面附加一個返回 boolean 的 when 條件,以進一步檢查。使用它的常見場景就是當值為 null 時。

using System;

public abstract class Shape
{
   public abstract double Area { get; }
   public abstract double Circumference { get; } 
}

public class Rectangle : Shape
{
   public Rectangle(double length, double width) 
   {
      Length = length;
      Width = width; 
   }

   public double Length { get; set; }
   public double Width { get; set; }
   
   public override double Area
   { 
      get { return Math.Round(Length * Width,2); } 
   } 
   
   public override double Circumference 
   {
      get { return (Length + Width) * 2; }
   }
}

public class Square : Rectangle
{
   public Square(double side) : base(side, side) 
   {
      Side = side; 
   }

   public double Side { get; set; }
}

public class Circle : Shape
{
   public Circle(double radius) 
   {
      Radius = radius;
   } 
   
   public double Radius { get; set; }

   public override double Circumference
   {
      get { return 2 * Math.PI * Radius; }
   }

   public override double Area
   {
      get { return Math.PI * Math.Pow(Radius, 2); } 
   }
}

public class Example
{
   public static void Main()
   {
      Shape sh = null;
      Shape[] shapes = { new Square(10), new Rectangle(5, 7),
                         sh, new Square(0), new Rectangle(8, 8),
                         new Circle(3) };
      foreach (var shape in shapes)
         ShowShapeInfo(shape);
   }

   private static void ShowShapeInfo(Shape sh)
   {
      switch (sh)
      {
         // Note that this code never evaluates to true.
         case Shape shape when shape == null:
            Console.WriteLine($"An uninitialized shape (shape == null)");
            break;
         case null:
            Console.WriteLine($"An uninitialized shape");
            break;
         case Shape shape when sh.Area == 0:
            Console.WriteLine($"The shape: {sh.GetType().Name} with no dimensions");
            break;
         case Square sq when sh.Area > 0:
            Console.WriteLine("Information about square:");
            Console.WriteLine($"   Length of a side: {sq.Side}");
            Console.WriteLine($"   Area: {sq.Area}");
            break;
         case Rectangle r when r.Length == r.Width && r.Area > 0:
            Console.WriteLine("Information about square rectangle:");
            Console.WriteLine($"   Length of a side: {r.Length}");
            Console.WriteLine($"   Area: {r.Area}");
            break;
         case Rectangle r when sh.Area > 0:
            Console.WriteLine("Information about rectangle:");
            Console.WriteLine($"   Dimensions: {r.Length} x {r.Width}");
            Console.WriteLine($"   Area: {r.Area}");
            break;
         case Shape shape when sh != null:
            Console.WriteLine($"A {sh.GetType().Name} shape");
            break;
         default:
            Console.WriteLine($"The {nameof(sh)} variable does not represent a Shape.");
            break;   
      }
   }
}
// The example displays the following output:
//       Information about square:
//          Length of a side: 10
//          Area: 100
//       Information about rectangle:
//          Dimensions: 5 x 7
//          Area: 35
//       An uninitialized shape
//       The shape: Square with no dimensions
//       Information about square rectangle:
//          Length of a side: 8
//          Area: 64
//       A Circle shape

 

 

其它資源:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM