C#8.0中新语法“is {}“的介绍及使用

一、C#7.0及之前is的使用

is操作符检查表达式的结果是否与给定类型兼容,或者(从c# 7.0开始)根据模式测试表达式。有关类型测试is操作符的信息,请参阅类型测试和类型转换操作符文章的is操作符部分。

1、is 模式匹配

从C#7.0开始,isswitch语句支持模式匹配。该is关键字支持以下模式:

Type模式:它测试表达式是否可以转换为指定的类型,如果可以,则将其强制转换为该类型的变量。

(Constant)常量模式:用于测试表达式是否求值为指定的常量值。

var模式:匹配成功并且将表达式的值绑定到新的局部变量的匹配。

从C#7.1开始,expr可能具有由通用类型参数及其约束定义的编译时类型。

如果exprtrue并且isif语句一起使用,则varname仅在if语句内分配。varname的范围是从is表达式到包含if语句的块末尾。在其他任何位置使用varname会导致使用尚未分配的变量时产生编译时错误。

  1. Type模式

使用类型模式执行模式匹配时,is测试表达式是否可以转换为指定的类型,如果可以,将其强制转换为该类型的变量。这是对is语句的直接扩展,可以实现简洁的类型评估和转换。is类型模式的一般形式是:

复制代码
  expr is type varname

下面的示例使用is类型模式提供类型的IComparable.CompareTo(Object)方法的实现。

复制代码
using System;

public class Employee : IComparable
{
    public String Name { get; set; }
    public int Id { get; set; }

    public int CompareTo(Object o)
    {
        if (o is Employee e)
        {
            return Name.CompareTo(e.Name);
        }
        throw new ArgumentException("o is not an Employee object.");
    }
}
  1. (Constant)常量模式

使用常量模式执行模式匹配时,is测试表达式是否等于指定的常量。在C#6和更早版本中,switch语句支持常量模式。从C#7.0开始,该is语句也支持它。其语法为:

复制代码
expr is constant

以下示例将类型和常量模式组合在一起,以测试对象是否为Dice实例,如果是,则确定掷骰的值是否为6。

复制代码
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!

null可以使用 (Constant)常量进行检查。该语句null支持关键字is。其语法为:

复制代码
expr is null

示例代码:

复制代码
using System;
class Program
{
    static void Main(string[] args)
    {
        object o = null;
        if (o is null)
        {
            Console.WriteLine("o does not have a value");
        }
        else
        {
            Console.WriteLine($"o is {o}");
        }
        int? x = 10;
        if (x is null)
        {
            Console.WriteLine("x does not have a value");
        }
        else
        {
            Console.WriteLine($"x is {x.Value}");
        }
        // 'null' check comparison
        Console.WriteLine($"'is' constant pattern 'null' check result : { o is null }");
        Console.WriteLine($"object.ReferenceEquals 'null' check result : { object.ReferenceEquals(o, null) }");
        Console.WriteLine($"Equality operator (==) 'null' check result : { o == null }");
    }
    // The example displays the following output:
    // o does not have a value
    // x is 10
    // 'is' constant pattern 'null' check result : True
    // object.ReferenceEquals 'null' check result : True
    // Equality operator (==) 'null' check result : True
}
  1. var模式

与var模式匹配的模式总是成功。它的语法是:

复制代码
expr is var varname

expr的值总是分配给一个名为varname的局部变量。varname是与expr的编译时类型相同的变量。

如果expr的计算结果为null,则is表达式生成true并将null赋值给varname。var模式是is为数不多的对空值产生true的用法之一。

你可以使用var模式在一个布尔表达式中创建一个临时变量,如下面的例子所示:

复制代码
using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
    static void Main()
    {
        int[] testSet = { 100271, 234335, 342439, 999683 };
        var primes = testSet.Where(n => Factor(n).ToList() is var factors
                                    && factors.Count == 2
                                    && factors.Contains(1)
                                    && factors.Contains(n));
        foreach (int prime in primes)
        {
            Console.WriteLine($"Found prime: {prime}");
        }
    }
    static IEnumerable<int> Factor(int number) 
    {
        int max = (int)Math.Sqrt(number);
        for (int i = 1; i <= max; i++) 
        {
            if (number % i == 0)
            {
                yield return i;
                if (i != number / i) 
                {
                    yield return number / i;
                }
            }
        }
    }
}
// The example displays the following output:
//       Found prime: 100271
//       Found prime: 999683

二、C# 8.0中is的新语法

属性模式

匹配任何非"null"且属性设置为Length为2的对象,示例代码如下:

复制代码
if (value is { Length: 2 })
{ 
}

实现验证的示例:

复制代码
public async Task<IActionResult> Update(string id, ...) 
{
    if (ValidateId(id) is { } invalid)
        return invalid;
    ...
}

上面的例子中,ValidateId()可以返回nullBadObjectRequestResult的一个实例。如果返回了前者,验证就成功了,并转移到更新主体的其余部分。如果返回的是后者,则is{}为真(也就是说,当然BadObjectRequestResult的实例是一个对象),验证失败。

如果使用一般写法做个判断,可能需要更多的代码,如下:

复制代码
public async Task<IActionResult> Update(string id, ...) 
{
    var invalid = ValidateId(id);
    if (invalid != null)
        return invalid;
    ...
}

相关文档The `is` operator - Match an expression against a type or constant pattern - C# | Microsoft Learn

相关推荐
2202_75442154几秒前
生成MPSOC以及ZYNQ的启动文件BOOT.BIN的小软件
java·linux·开发语言
我只会发热7 分钟前
Java SE 与 Java EE:基础与进阶的探索之旅
java·开发语言·java-ee
懷淰メ17 分钟前
PyQt飞机大战游戏(附下载地址)
开发语言·python·qt·游戏·pyqt·游戏开发·pyqt5
hummhumm31 分钟前
第 22 章 - Go语言 测试与基准测试
java·大数据·开发语言·前端·python·golang·log4j
宁静@星空37 分钟前
006-自定义枚举注解
java·开发语言
hummhumm1 小时前
第 28 章 - Go语言 Web 开发入门
java·开发语言·前端·python·sql·golang·前端框架
武子康1 小时前
Java-07 深入浅出 MyBatis - 一对多模型 SqlMapConfig 与 Mapper 详细讲解测试
java·开发语言·数据库·sql·mybatis·springboot
珹洺1 小时前
C语言数据结构——详细讲解 双链表
c语言·开发语言·网络·数据结构·c++·算法·leetcode
每天吃饭的羊1 小时前
python里的数据结构
开发语言·python
码农飞飞1 小时前
详解Rust枚举类型(enum)的用法
开发语言·rust·match·枚举·匹配·内存安全