需要在C#中使用IS运算符

时间:2017-02-09 13:57:04

标签: c# .net casting

在C#中有is运算符用于检查对象是否与某种类型兼容。此运算符尝试将对象强制转换为某种类型,如果转换成功则返回true(如果转换失败,则返回false。)

来自Jeffrey Richter CLR via C#

  

is运算符检查对象是否与给定对象兼容   类型,评估结果是布尔值:true或false。

if (o is Employee) 
{
    Employee e = (Employee) o;
    // Use e within the remainder of the 'if' statement.
}
  

在此代码中,CLR实际上是两次检查对象的类型:   is运算符首先检查o是否与o兼容   员工类型。如果是,则在if语句中再次使用CLR   在执行演员表时验证o是否引用了Employee。该   CLR的类型检查提高了安全性,但肯定会出现这种情况   性能成本,因为CLR必须确定实际类型   变量(o)引用的对象,然后CLR必须行走   继承层次结构,检查每个基类型   指定类型(员工)。

另外,从同一本书:

Employee e = o as Employee;
if (e != null) 
{
    // Use e within the 'if' statement.
}
  

在此代码中,CLR检查o是否与Employee兼容   type,如果是,则返回对它的非null引用   宾语。如果o与Employee类型不兼容,则为as运算符   返回null。请注意,as运算符会导致CLR验证   对象的类型只有一次。 if语句只检查e是否为   空值;这种检查可以比验证对象更快地执行   类型。

所以,我的问题是:为什么我们需要is运算符? is运营商优于as的情况更为明显。

4 个答案:

答案 0 :(得分:8)

  

为什么我们需要的是运营商?

我们不需要它。这是多余的。如果is运算符不在语言中,您可以通过简单地编写

来模拟它
(x as Blah) != null

用于参考类型和

(x as Blah?) != null

表示值类型。

事实上,这就是所有is;如果查看IL,isas都会编译为相同的IL指令。

你的第一个问题无法回答,因为它假定是虚假的。为什么我们需要这个运营商?我们需要它,所以没有理由为什么我们需要它。所以这不是一个富有成效的问题。

  

当运营商比作为运营商更优选的时候是哪种情况。

我想你想问一下

  

为什么我要写#"效率低下"执行两次类型检查的代码 - is后跟一个强制转换 - 当我可以编写使用as和空检查进行一种类型检查的高效代码时?

首先,效率的论点很弱。类型检查很便宜,即使价格昂贵,它们也可能不是你做的最贵的事情。不要为了节省那几纳秒而改变看起来非常合理的代码。如果您认为代码看起来更好或使用is而不是as更容易阅读,那么请使用is而不是as。目前市场上没有产品使用as vs is来确定成功或失败。

或者,从另一个角度看待它。 isas都证明您的程序甚至不知道值的类型是什么,以及编译器无法解决类型的程序是(1)越野车,(2)慢。如果你非常关心速度,那就不要编写一个类型测试的程序,而不是两个;编写执行类型测试的程序而不是一个!编写可以静态确定打字的程序。

其次,在C#中你需要一个表达式,而不是一个语句,而C#很遗憾没有" let"查询之外的表达式。你可以写

... e is Manager ? ((Manager)e).Reports : 0 ...

作为表达但在C#7之前没有办法写

Manager m = e as Manager;

在表达式上下文中。在查询中,您可以编写

from e in Employees
select e is Manager ? ((Manager)e).Reports : 0

from e in Employees 
let m = e as Manager
select m == null ? 0 : m.Reports

但没有"让"在查询之外的表达式上下文中。能够写

会很高兴
... let m = e as Manager in m == null ? 0 : m.Reports ...  

以任意表达式。但我们可以在那里找到一些方法。在C#7中,您(可能)能够写出

e is Manager m ? m.Reports : 0 ...

这是一个很好的糖,消除了低效的复核。 is - with-new-variable语法很好地将所有内容组合在一起:你得到一个布尔类型测试一个命名的类型化引用。

现在,我刚才说的是一个轻微的谎言;从C#6开始,您可以将上面的代码编写为

(e as Manager)?.Reports ?? 0

进行一次类型检查。但在C#6.0之前,你运气不好;如果你在表达式上下文中,你几乎总是必须进行两次类型检查。

答案 1 :(得分:2)

使用C#7,is运算符as可能不那么冗长。Employee e = o as Employee; if (e != null) { // Use e within the 'if' statement. }
比较这个

if (o is Employee e) 
{
    // Use e within the 'if' statement.
}

和这个

<ul> </ul>

来自here的信息。 与表达式匹配的模式

答案 2 :(得分:1)

有些时候,您可能只想检查类型,而不是实际投入它。

因此,您可以使用is运算符来确认您的对象是兼容的,并执行您想要的任何逻辑。而在其他情况下,您可能只想(安全地或其他方式)投射并使用返回的值。

最终因为is只返回一个布尔值,你可以用它来检查。 as(T)MyType类型转换用于安全地转换为null或分别投掷Exception

<强> How to: Safely Cast by Using as and is Operators (C# Programming Guide)

答案 3 :(得分:1)

我能想到的至少一个用例是在比较某个变量是否为值类型时(as在这种情况下不能使用)。

例如,

var x = ...;
if(x is bool)
{
    // do something
}

当你不一定需要使用强制转换时它也很有用,但只是感兴趣某事物是否属于某种基础类型。