is(C# 参考)is (C# Reference)

is 运算符检查表达式的结果是否与给定类型兼容,或(从 C# 7.0 开始)针对某个模式测试表达式。The is operator checks if the result of an expression is compatible with a given type, or (starting with C# 7.0) tests an expression against a pattern. 有关类型测试 is 运算符的信息,请参阅文章类型测试和强制转换运算符is 运算符部分。For information about the type-testing is operator see the is operator section of the Type-testing and cast operators article.

利用 is 的模式匹配Pattern matching with is

从 C# 7.0 开始,isswitch 语句支持模式匹配。Starting with C# 7.0, the is and switch statements support pattern matching. is 关键字支持以下模式:The is keyword supports the following patterns:

  • 类型模式,用于测试表达式是否可转换为指定类型,如果可以,则将其转换为该类型的一个变量。Type pattern, which tests whether an expression can be converted to a specified type and, if it can be, casts it to a variable of that type.

  • 常量模式,用于测试表达式计算结果是否为指定的常数值。Constant pattern, which tests whether an expression evaluates to a specified constant value.

  • var 模式,始终成功的匹配,可将表达式的值绑定到新局部变量。var pattern, a match that always succeeds and binds the value of an expression to a new local variable.

类型模式Type pattern

使用类型模式执行模式匹配时,is 会测试表达式是否可转换为指定类型,如果可以,则将其转换为该类型的一个变量。When using the type pattern to perform pattern matching, is tests whether an expression can be converted to a specified type and, if it can be, casts it to a variable of that type. 它是 is 语句的直接扩展,可执行简单的类型计算和转换。It's a straightforward extension of the is statement that enables concise type evaluation and conversion. is 类型模式的一般形式为:The general form of the is type pattern is:

   expr is type varname

其中 expr 是计算结果为某个类型的实例的表达式,typeexpr 结果要转换到的类型的名称,varnameexpr 结果要转换到的对象(如果 is 测试为 true)。where expr is an expression that evaluates to an instance of some type, type is the name of the type to which the result of expr is to be converted, and varname is the object to which the result of expr is converted if the is test is true.

如果 expr 不为 null 且以下任意内容为 true,那么 is 表达式为 trueThe is expression is true if expr isn't null, and any of the following is true:

  • expr 是与 type 具有相同类型的一个实例。expr is an instance of the same type as type.

  • expr 是派生自 type 的类型的一个实例。expr is an instance of a type that derives from type. 换言之,expr 结果可以向上转换为 type 的一个实例。In other words, the result of expr can be upcast to an instance of type.

  • expr 具有属于 type 的一个基类的编译时类型,expr 还具有属于 type 或派生自 type 的运行时类型。expr has a compile-time type that is a base class of type, and expr has a runtime type that is type or is derived from type. 变量的编译时类型 是其声明中定义的变量类型。The compile-time type of a variable is the variable's type as defined in its declaration. 变量的运行时类型 是分配给该变量的实例类型。The runtime type of a variable is the type of the instance that is assigned to that variable.

  • expr 是实现 type 接口的类型的一个实例。expr is an instance of a type that implements the type interface.

自 C# 7.1 起,expr 可能有泛型类型参数及其约束定义的编译时类型。Beginning with C# 7.1, expr may have a compile-time type defined by a generic type parameter and its constraints.

如果 exprtrueisif 语句配合使用,则仅在 if 语句内分配 varnameIf expr is true and is is used with an if statement, varname is assigned within the if statement only. varname 的使用范围:从 is 表达式到封闭 if 语句的块的末尾。The scope of varname is from the is expression to the end of the block enclosing the if statement. 在任何其他位置使用 varname 都会因使用尚未分配的变量而生成编译时错误。Using varname in any other location generates a compile-time error for use of a variable that has not been assigned.

下列示例使用 is 类型模式为类型的 IComparable.CompareTo(Object) 方法提供实现。The following example uses the is type pattern to provide the implementation of a type's IComparable.CompareTo(Object) method.

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.");
    }
}

如果没有模式匹配,则可能按以下方式编写此代码。Without pattern matching, this code might be written as follows. 使用类型模式匹配无需测试转换结果是否为 null,从而生成更紧凑易读的代码。The use of type pattern matching produces more compact, readable code by eliminating the need to test whether the result of a conversion is a null.

using System;

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

    public int CompareTo(Object o)
    {
        var e = o as Employee;
        if (e == null)
        {
           throw new ArgumentException("o is not an Employee object.");
        }
        return Name.CompareTo(e.Name);
    }
}

确定值类型的类型时,is 类型模式也会生成更紧凑的代码。The is type pattern also produces more compact code when determining the type of a value type. 下例在显示相应属性的值之前使用 is 类型模式来确定对象是 Person 还是 Dog 实例。The following example uses the is type pattern to determine whether an object is a Person or a Dog instance before displaying the value of an appropriate property.

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

对于无模式匹配的等效代码,需要为其单独分配显式转换。The equivalent code without pattern matching requires a separate assignment that includes an explicit cast.

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) {
         Person p = (Person) o;
         Console.WriteLine(p.Name);
      }   
      else if (o is Dog) {
         Dog d = (Dog) o;
         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

常量模式Constant pattern

使用常量模式执行模式匹配时,is 会测试表达式结果是否等于指定常量。When performing pattern matching with the constant pattern, is tests whether an expression equals a specified constant. 在 C# 6 和更低版本中,switch 语句支持常量模式。In C# 6 and earlier versions, the constant pattern is supported by the switch statement. 自 C# 7.0 起,is 语句也支持它。Starting with C# 7.0, it's supported by the is statement as well. 语法为:Its syntax is:

   expr is constant

其中 expr 是要计算的表达式,constant 是要测试的值。where expr is the expression to evaluate, and constant is the value to test for. constant 可以是以下任何常数表达式:constant can be any of the following constant expressions:

  • 一个文本值。A literal value.

  • 已声明 const 变量的名称。The name of a declared const variable.

  • 一个枚举常量。An enumeration constant.

常数表达式的计算方式如下:The constant expression is evaluated as follows:

  • 如果 exprconstant 均为整型类型,则 C# 相等运算符确定表示式是否返回 true(即,是否为 expr == constant)。If expr and constant are integral types, the C# equality operator determines whether the expression returns true (that is, whether expr == constant).

  • 否则,由对静态 Object.Equals(expr, constant) 方法的调用来确定表达式的值。Otherwise, the value of the expression is determined by a call to the static Object.Equals(expr, constant) method.

下例同时使用了类型模式和常量模式来测试对象是否为 Dice 实例,如果是,则确定骰子的值是否为 6。The following example combines the type and constant patterns to test whether an object is a Dice instance and, if it is, to determine whether the value of a dice roll is 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 检查。Checking for null can be performed using the constant pattern. is 语句支持 null 关键字。The null keyword is supported by the is statement. 语法为:Its syntax is:

   expr is null

下面的示例显示 null 检查的比较:The following example shows a comparison of null checks:

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
}

var 模式var pattern

var 模式对于任何类型或值均为 catch-all。The var pattern is a catch-all for any type or value. expr 值始终分配给与 expr 的编译时类型相同的本地变量。The value of expr is always assigned to a local variable the same type as the compile time type of expr. is 表达式的结果始终为 trueThe result of the is expression is always true. 语法为:Its syntax is:

   expr is var varname

下例使用 var 模式向名为 obj 的变量分配表达式。The following example uses the var pattern to assign an expression to a variable named obj. 然后,显示 obj 的值和类型。It then displays the value and the type of obj.

using System;

class Program
{
    static void Main()
   {
      object[] items = { new Book("The Tempest"), new Person("John") };
      foreach (var item in items) {
        if (item is var obj)
          Console.WriteLine($"Type: {obj.GetType().Name}, Value: {obj}"); 
      }
   }
}

class Book
{
    public Book(string title) 
    {
       Title = title;    
    }

    public string Title { get; set; }

    public override string ToString()
    {
       return Title;
    }
}

class Person
{
   public Person(string name)
   {
      Name = name;
   }

   public string Name 
   { get; set; }

   public override string ToString()
   {
      return Name;
   }
}
// The example displays the following output:
//       Type: Book, Value: The Tempest
//       Type: Person, Value: John

C# 语言规范C# language specification

有关详细信息,请参阅 C# 语言规范is 运算符部分以及下面的 C# 语言建议:For more information, see The is operator section of the C# language specification and the following C# language proposals:

请参阅See also