一种机制,与js类似

我们知道,当两个条件进行逻辑与操作的时候,其中任何一个条件为假,则表达式的结果为假。所以,遇到(A 且 B)这种表达式,如果A为假的话,B是不是真假都无所谓了,当遇到一个假条件的时候,程序也就没有必要去额外的判断剩下的东西了

C#语言中也是如此。当多个条件进行逻辑与操作的时候,判定会从表达式左边执行到右边,遇到任何一个为假,后面就都不做了。这很聪明,然而如果后面的条件会抛出异常,就是个潜在的问题。一旦之前的条件为真,就会继续执行,执行到抛出异常的条件时,程序就爆了,哈哈。
我们可以写个简单的demo试试。下面的这段代码是坑爹的,之后我会说明原因,但大家可以先从直观的层面上理解一下,最后我会给出正确的测试方法。

复制代码 代码如下:

static void Main(string[] args)
{
DataSet ds = null;
if (false && ds.Tables[0].Rows.Count > 0)
{
Console.WriteLine("Fuck");
}
else
{
Console.WriteLine("Shit");
}
if (true && ds.Tables[0].Rows.Count > 0)
{
Console.WriteLine("WOW");
}
else
{
Console.WriteLine("KAO");
}
Console.ReadKey();
}

这段代码乍看没问题,并且在运行时也给出了我们期望的结果,即第一段语句输出Shit,不抛出异常(当前面为false,后面会抛异常的ds.Tables[0].Rows.Count > 0就不做),而第二段语句因为之前是true,所以要执行对dataset的判断,所以抛出异常。但如果用reflector反编译程序集,就会发现,编译器已经把上面的代码优化成了下面这种形式,我们的if语句中写死的true和false已经被阉割掉了,所以并不能说明if语句执行的问题。

复制代码 代码如下:

private static void Main(string[] args)
{
DataSet ds = null;
Console.WriteLine("Shit");
if (ds.Tables[0].Rows.Count > 0)
{
Console.WriteLine("WOW");
}
else
{
Console.WriteLine("KAO");
}
Console.ReadKey();
}

其实,如果你仔细观察,在输入这段代码的过程中,VS就已经提示if (false && ds.Tables[0].Rows.Count > 0)中,后者是不可达的。这是即时编译的效果。既然即时编译说后面的代码不可达,就意味着不可达的代码会在编译期被切掉。因此,刚才我们在上面看到的编译结果也就是自然的事情了。
同样,如果你直接把1 == 0, 1 == 1这样的条件拼上去的话,编译器也会发现的。所以我们要找一种不会被编译器发现的写法,要让我们的条件判定代码只能在运行时执行,而不是编译时被调整。比如下面这种:

复制代码 代码如下:

static void Main(string[] args)
{
DataSet ds = null;
int i = 0;
int j = 1;
if (i + j == 0 && ds.Tables[0].Rows.Count > 0)
{
Console.WriteLine("Fuck");
}
else
{
Console.WriteLine("Shit");
}
if (i + j == 1 && ds.Tables[0].Rows.Count > 0)
{
Console.WriteLine("WOW");
}
else
{
Console.WriteLine("KAO");
}
Console.ReadKey();
}

我们再来执行,发现这次的结果是真正意义的满足了我们的目的,说明了当多个条件进行逻辑与的时候,C#的执行机制:

写这篇文章的意义,是为了让大家在写程序的时候,注意条件中可能发生异常的地方。比如我们模拟String.IsNullOrEmpty()。
在or关系中,只要有一个true,整个表达式就是true了。但如果你让可能引发异常的语句先于之后会返回true的语句执行,就会爆。
比如这样写的话会爆,因为判断Length的前提是得有个string:

复制代码 代码如下:

public static bool IsNullOrEmpty(string str)
{
if (str.Length == 0 || str == null)
{
return true;
}
return false;
}

这样写就正常:

复制代码 代码如下:

public static bool IsNullOrEmpty(string str)
{
if (str == null || str.Length == 0)
{
return true;
}
return false;
}

微软是这样写的,碉堡了!

复制代码 代码如下:

public static bool IsNullOrEmpty(string value)
{
if (value != null)
{
return (value.Length == 0);
}
return true;
}

上面这段代码可以用reflector打开mscorlib中的System.String找到~

您可能感兴趣的文章:

时间: 2024-10-11 00:42:48

一种机制,与js类似的相关文章

利用内核cgroup机制轻松实现类似docker的系统资源管控

近几年,以docker为代表的容器技术异常火热,它的轻量.高效让人欣喜若狂,它被赋予了改变传统IT运维的使命.相信随着时间推移,以容器云为落地形式的产品将真正实现这一使命. 我们都知道docker能够实现资源的隔离和控制,正当打算引入docker来管理产品不同业务的资源占用时,发现它的隔离性是我们所不需要的,而我们都知道,docker底层实际上是利用了linux内核提供的namespace和cgroup机制,而前者是用于资源隔离的,后者是用于资源控制的.这时,我们想到了直接用cgroup来实现.

进程同步的几种机制

转自: http://www.cnblogs.com/sonic4x/archive/2011/07/05/2098036.html 多进程的系统中避免不了进程间的相互关系.本讲将介绍进程间的两种主要关系——同步与互斥,然后着重讲解解决进程同步的几种机制.       进程互斥是进程之间发生的一种间接性作用,一般是程序不希望的.通常的情况是两个或两个以上的进程需要同时访问某个共享变量.我们一般将发生能够问共享变量的程序段称为临界区.两个进程不能同时进入临界区,否则就会导致数据的不一致,产生与时间

uploadify v3.2.1 上传报大量js 类似__flash__addCallback(document.getElementById("SWFUpload_0"), "ReturnUploadStart"); 错误

报__flash__addCallback未定义 报__flash__removeCallback未定义 最后解决方法:  uploadify  提供了destroy方法,每次使用完后,清空就可以了. 在body 中添加 onunload="checkLeave()" 方法. function checkLeave() { if ($('#btn_upload').length > 0) { $('#btn_upload').uploadify('destroy'); } } o

Intent传输数据的几种机制

1.Intent是什么 Intent是视图的意思,它是Android应用内不同组件之间通信的载体.当Android运行时需要连接不同的组件时,通常就需要借助于Intent来实现.Intent可以启动应用中另一个Activity,也可以启动一个Service组件,还可以发送一条广播消息来触发系统中的BroadcastReceiver.Activity,Service和BroadcastReceiver三个组件之间的通信都以Intent作为载体. (1)启动一个Activity时,可以调用Conte

Python -- 值转换为字符串的两种机制

可以通过以下两个函数来使用这两种机制:一是通过str函数,它会把值转换为合理形式的字符串,以便用户可以理解:而repr会创建一个字符串,它以合法的Python表达式的形式来表示值.下面是一些例子: >>> print repr("Hello, world!") 'Hello, world!' >>> print repr(10000L) 10000L >>> print str("Hello, world!")

JS类似Java String.format的函数

String.prototype.format = String.prototype.f = function () { var s = this, i = arguments.length; while (i--) {s = s.replace(new RegExp('\\{' + i + '\\}', 'gm'), arguments[i]); } return s;}; "chen {0} hua".format("zeng") JS类似Java String

SOCKET是调用操作系统通信服务的一种机制

有没有SOCKET,网卡都会接收数据.网卡工作在数据链路层,它只认识链路上邻近的点.它甚至不认识它隔壁的隔壁,它又怎么可能知道传输层的信息呢(起点与终点,是传输层的信息)?...传输层的信息,只能由传输层来处理! IP层存在同样的问题.因为它也"活(动)"在网络层.它也不处理,同样地它也不能处理本来位于第四层即传输层的与传输相关的信息..当然,如果一个网络节点硬要处理它,当然也是可以的.因为高层的信息是被低层的信息所包裹着的.只是恐怕一般的机构没有这样的实力来做这个事情.因为那么多人的

三种方法实现js跨域访问

javascript跨域访问是web开发者经常遇到的问题,什么是跨域,一个域上加载的脚本获取或操作另一个域上的文档属性,下面将列出三种实现javascript跨域方法: 1.基于iframe实现跨域 基于iframe实现的跨域要求两个域具有aa.xx.com,bb.xx.com这种特点,也就是两个页面必须属于一个基础域(例如都是xxx.com,或是xxx.com.cn),使用同一协议(例如都是 http)和同一端口(例如都是80),这样在两个页面中同时添加document.domain,就可以实

25Spring_事务管理的两种机制

一共有两种事务管理机制:编程式事务管理和声明式事务管理. 1.编程式事务管理企业已经不用了. 2.我们主要讲的是声明式事务管理.声明式事务管理 ,无需要修改原来代码,只需要配置,为目标代码添加事务管理 , AOP底层实现 --- 企业推荐 下面写一个案例:通过Spring声明式事务管理.实现转账案例. 第一步:建表: 建表语句如下:account中有两个账户(aaa和bbb) CREATE TABLE `account` ( `id` int(11) NOT NULL AUTO_INCREMEN