这个问题初看起来很奇怪,C#就是C#啊,一门严谨的语言,并且字符串是区分大小写的,无论是在什么情况下都有("x" != "X"),这才叫做一致性嘛。事实上,这在以前一直都是成立的,直到.NET Framework 3.5引入了Linq to Sql,这种一致性就被破坏掉了,变成依赖于环境配置了。
想象一下我们对一个Linq to Sql的DataObject编写一个Linq查询,并且where子句包括("x" == "X"),那么该子句会返回true还是false呢?事实上,该查询虽然是一个用C#编写的lamda表达式,然而并不编译为MSIL。Linq to Sql里面的Linq是直接编译为SQL语句的,因此("x" == "X")会直接变成SQL里面的("x" = "X")。那么这就为true了?也不对,因为大小写是否敏感是基于数据库配置的,在当前的应用程序连接上特定的数据库之前,这个问题的答案都是不确定的。
那么我们可否选择使用String.Compare()来强制设置是否大小写敏感?这在Linq to Object中没问题,在Linq to Sql中就不行了,因为String.Compare()无法编译为SQL语句。因此,在Linq to Sql中,大小写是否敏感是一个依赖于环境配置的,这就提高了编码过程中由于疏忽而造成问题的概率。
为什么这样说呢?在以前,我们的C#代码和SQL代码是分开书写的,写C#的时候就很明确大小写敏感,写SQL的时候就很明确是数据库相关的。然而现在部分的SQL逻辑改为用C#来编写了,问题就出现了,特别是当你的代码中还混杂有Linq to Object的查询时,编写代码与阅读代码的过程中你一看到Linq就先要去想这段lamda表达式最终会被编译为哪种语言,MSIL还是SQL。如果你不进行这个区分,或者开小差把Linq to Sql的代码当作Linq to Object了,这就可能导致你编写了错误的代码,或者阅读上造成了错误的理解。
总体而言,虽然Linq to Sql为开发(特别是RAD)带来了巨大的便捷性,然而这种C#与SQL混合编写并且都使用C#语法的功能将会是一种先天的不足,它所带来的代码维护成本可能随着项目体积逐步增大而慢慢体现出来。至于将SQL混入C#所造成的分层模糊现象,我将在以后的文章中讨论,敬请关注:
Feedback
道理基本上是对的,不过一个细节有点问题。Linq经过编译后还是成为MSIL,还是.net代码,而那些Sql语句是由.net代码生成的。
例如下面的Linq:
var orders = from o in db.Orders
where o.OrderID > 10
orderby o.Name
select o;
编译之后其实是成为:
var orders = db.Orders.Where(o => o.OrderID > 10).OrderBy(o => o.Name);
上面的这句代码其实完全可以自己写。虽然还是有Lambda表达式,但是最终Lambda表达式会被编译成匿名类和其他一些东西。
其实用Reflector看看最终的那句代码,就会发现是这样的:
IOrderedQueryable<Order> orders = db.Orders.Where<Order>(Expression.Lambda<Func<Order, bool>>(Expression.GreaterThan(Expression.Property(CS$0$0000 = Expression.Parameter(typeof(Order), "o"), (MethodInfo) methodof(Order.get_OrderID)), Expression.Constant(10, typeof(int))), new ParameterExpression[] { CS$0$0000 })).OrderBy<Order, string>(Expression.Lambda<Func<Order, string>>(Expression.Property(CS$0$0000 = Expression.Parameter(typeof(Order), "o"), (MethodInfo) methodof(Order.get_Name)), new ParameterExpression[] { CS$0$0000 }));
所以其实Linq to Sql还是一个ORM框架,只是得到了语言方面的支持。
@Jeffrey Zhao
嗯……每一个子句最后还是lamda表达式的调用,不过Single()好像不能写成纯粹表达式,是吗?
@Cat Chen
好像是的……用了Single就到Linq to Object了。
// 似乎Linq to Sql支持的Operator是Linq标准Operator的子集
// 看看这个?ms-help://MS.MSDNQTR.v90.en/dv_linqsql/html/a60c30fa-1e68-45fe-b984-f6abb9ede40e.htm
Linq to Sql 与 Linq to Object 区别关键就看主查询对象是实现了IQueryable接口还是实现了IEnumerable接口。
IEnumerable就翻译成Delegate,IQueryable就翻译成Expression Tree
"结果依赖于配置" 这个说的很好,这就是 linq 的思想吧,至于 '==' 运算符的含义只是被扩展了一下,借用了一下老的 C# 语法。
各人认识问题,仁者见仁,智者见智,各有所好,我倒是认为既然是针对数据库的功能,那么和数据库匹配倒是正确的。如果 Linq to Collection 等也不区分大小写倒是有问题了!
@MyNameEPC
然而在一大堆代码中,你必须依赖于上下文才能看出某一句Linq是不是Linq to Sql,对吧?这时候就导致了代码的耦合度增加了。
很期待你的Repeater等数据控件是如何工作的文章,目前正被动态控件搞的头昏脑涨的,希望你的文章能使我茅塞顿开。
@asdfgh129
谢谢支持。我正在想如何能够把书中要一章才能讲完的内容,用一篇文章解释清楚,不深究细节的同时起码能让读者有个感性认识。
--引用--------------------------------------------------
Justin: 关注,一直还没研究过 Linq 呢
--------------------------------------------------------
Visual Basic 中,可以开启 Option Compare Text 实现不区分大小写的字符串比较。当然,这是运行库的支持。
@随风流月
VB还有那么丰富的功能啊,看来它的编译器真的能做很多提供便利的工作哦。