C#中的IS运算符需要

Dix*_*ixy 1 .net c# 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.
}
Run Code Online (Sandbox Code Playgroud)

在此代码中,CLR实际上是两次检查对象的类型:is运算符首先检查o是否与Employee类型兼容.如果是,则在if语句中,CLR再次验证o在执行强制转换时o引用Employee.CLR的类型检查提高了安全性,但肯定会带来性能成本,因为CLR必须确定变量(o)引用的对象的实际类型,然后CLR必须遍历继承层次结构,检查每个基类型针对指定的类型(Employee).

另外,从同一本书:

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

在此代码中,CLR检查o是否与Employee类型兼容,如果是,则返回对同一对象的非null引用.如果o与Employee类型不兼容,则as运算符返回null.请注意,as运算符使CLR只验证对象的类型一次.if语句只检查e是否为null; 可以比验证对象的类型更快地执行此检查.

所以,我的问题是:为什么我们需要is运营商?当is操作员更优选的情况下是哪种情况as.

Eri*_*ert 8

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

我们不需要它.这是多余的.如果is操作员不在语言中,您可以通过简单的写作来模拟它

(x as Blah) != null
Run Code Online (Sandbox Code Playgroud)

用于参考类型和

(x as Blah?) != null
Run Code Online (Sandbox Code Playgroud)

对于价值类型.

事实上,这就是全部is; 如果你看一下IL,都isas向下编译到相同的IL指令.

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

哪个是运营商比什么时候更优选的情况.

我想你想问

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

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

或者,从另一个角度来看待它.两者isas有证据证明你的程序甚至不知道一个值的类型是什么,并在编译器不能工作的各类方案往往是:(1)越野车,和(2)慢.如果你非常关心速度,不要编写一个类型测试的程序,而不是两个; 编写执行类型测试的程序而不是一个!编写可以静态确定打字的程序.

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

... e is Manager ? ((Manager)e).Reports : 0 ...
Run Code Online (Sandbox Code Playgroud)

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

Manager m = e as Manager;
Run Code Online (Sandbox Code Playgroud)

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

from e in Employees
select e is Manager ? ((Manager)e).Reports : 0
Run Code Online (Sandbox Code Playgroud)

要么

from e in Employees 
let m = e as Manager
select m == null ? 0 : m.Reports
Run Code Online (Sandbox Code Playgroud)

但是在查询之外的表达式上下文中没有"let".能够写作会很高兴

... let m = e as Manager in m == null ? 0 : m.Reports ...  
Run Code Online (Sandbox Code Playgroud)

在任意表达中.但我们可以在那里找到一些方法.在C#7中你(可能)能够写作

e is Manager m ? m.Reports : 0 ...
Run Code Online (Sandbox Code Playgroud)

这是一个很好的糖,消除了低效的复核.该is-with-新变量语法结合了精美的一切融合在一起:你得到一个布尔类型的测试,并命名,类型引用.

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

(e as Manager)?.Reports ?? 0
Run Code Online (Sandbox Code Playgroud)

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