论C#未来发展

近日M#的消息令江湖再次起了波澜。大家知道,.NET已经进入了瓶颈期。这个消息又让偶有所期待,趁此机会发表一下个人的展望,对C#或者其继任者,不管是M#还是X#。

一、语法特性

1. using引入类型

using关键字在.NET中有两个意义,这里是指引入命名空间。要是支持using类型会带来很大方便,比如:

using System.Runtime.InteropServices.Marshall;   //可以直接调用Marshall类的静态方法和属性
using List<string>= StringList; //写起来不用再打<>

2. 变量命名空间

有时候,处理业务很复杂,即使在一个不能再分割的处理单元中也有许多变量,命名和组织成了一个头疼的问题,将这些封装成类又不值得。如果可以在声明变量或字段时定义命名空间,这个烦恼就能解决:

class ProductUtil{
namespace Price
{
float old;
float New;
float standard;
} float GetPrice(){
float Price.discount; //声明折扣
//计算价格...
return Price.New;
}
}

命名空间可以在方法内,也可以在类型内。声明命空间后,可以单独声明一个变量。

3. 用out声明变量.

有点经验的开发者会经常用Try-Parse避免产生异常,一般TryParse、TryGet这类方法都把结果传给用out声明的参数中,我总是在想,为什么这个参数要先声明呢?

int value;  //这个声明完全可以去掉,看起来不爽
if (int.TryParse(s, out value))
{
Console.WriteLine(value);
}

4. 省略属性字段

C# 3.0推出了简化属性的方式:public string Text { get;set; }。但还不彻底,对于get set内部有一定处理逻辑的,无法省略字段。如果可以用一个关键字代替字段,将使代码更整洁。

我觉得用default在属性内表示字段不错,如果在内部其他方法中要直接访问此字段(应该很谨慎地),可以用default(this.Text),好像有点麻烦,但这种情况很少,这样用会更醒目。

5. 能做就做

要说最烦的,还是这种判断代码

if(list !=  null && list.Count > ){
return list.Last();
}

很多时候,根本无需处理list为null或空的情况,如果上面的代码能可以写成这样,必然很受欢迎:

return list.Last()??;

从此以后,我们可以唱:兄弟你大胆地往下写哟~~,别怕异常~~

6. 带参构造函数约束

泛型约束只能声明无参构造函数,这种限制没任何道理。应可以像下面这样。

public class MyClass<T> where T : class, new(int) { ... }

或者不限制构造函数的参数:

public class MyClass<T> where T : class, new { ... }

如果调用了不兼容的构造函数,IDE完全可以在编译时检查出来。

7. case可跟表达式

刚学编程接触switch case时,就很不解case后面只能跟常量的限制。这其实应该是个bug,包括其他语言。

8. 扩展属性

当时扩展方法推出的时候,为什么没有扩展属性呢?我知道肯定有某种理由,但这个真可以有。

9. 绑定运算符

对于两个类实例 A=B 将使AB指向同一个引用,若随后B引用变化了,对A没有影响。许多初学者搞不清=运算符的作用,以为B变化,A也随之变化。

其实这种特性是C#一直都欠缺的,如果我们可以让 A==B 实现A和B的绑定(左边可以是表达式),那许多工作就轻松了。

要考虑GC的问题,如果A未被回收,B也不能被回收。

10. 项目引用Native dll

如今要调用C/C++的程序集,必须查好参数,转化类型,再像这种方式声明:

[DllImport("User32.dll", CharSet = CharSet.Unicode)]
public static extern int MessageBox(int h, string m, string c, int type);

为什么不能像引用.NET dll那样引用C/C++写的dll呢,或者像Service Reference那样,增加一个Native Reference的目录,自动生成代理类。

11. Fluent语法

利用语法糖,希望能够大幅减少关键字使用,比如对于(int)value, value as string都可以用ToSomeType()表示。若调用构造函数,可以省略new关键字。

在使用第一条using声明调用静态方法的类后,可以将静态方法作为任一参数的扩展方法。

using String;
static void SortDates(string dates)
{
var lstDates = dates.Split(',').Select(d=>d.ToDateTime()); //ToDateTime()相当于(DateTime)
var endDate = DateTime(lstDates.Max().Year, 12 ,); //省略new
dates = lstDates.OrderBy(d=>d).Join(","); //String.Join方法变扩展方法
}

12. 全局性配置

这其实是由Visual Studio实现的功能。如果实现扩展属性,直接调用类静态方法,会导致自动提示里拥挤不堪,让便利性打折扣。应该可以在项目属性里配置,导入一个配置模板,默认隐藏掉那些不常用的成员,比如所有类型都甩不掉的Equals/ReferenceEquals/GetHashCode。这个模板还可以用using为类型起别名,就不必在每个文件中一一声明了。

这样C#关键字会大大减少,还可以定制更加符合个人或团队习惯的命名。

这几天又想到两个特性,补充一下(1-11)

13. 真正的”转到定义“

F12转到方法的定义,多数时候很方便,但有两个很不方便的问题。一个是方法被子类override时,F12会转到父类的方法,这在开发时也就罢了,调试时VS完全知道真正调用的方法是否被覆写过,应该转到真正调用的方法上去。还有一个是客户端调用WCF或Service代理类的方法,F12不应转到代理类中,应该转到项目中WCF或Service方法的定义,除非是第三方的服务。查找引用时,也应该将Server/Client端代码一并包括。

14. 程序集自定义引用

引用一个程序集时,应该像安装程序一样,可以定义引用程序集哪些模块,这样就可以大大减小安装包和程序的体积。别说这是异想天开,CIL本身就支持Module的概念,只是现在编译器偷懒没有实现而已。

二、动态支持

C#的反射虽然很完善了,但性能还是差,并且相当不友好。如果要运行时修改代码,即使用最先进的Lamda Expression,还有第三方框架MonoCecil都很麻烦,更别说用Emit和Code Generator。所以C#基本上还是一门静态语言,这样满足诸如AOP这种高扩展性开发需求,仍然十分吃力。

我们早对一个基于项目的元数据框架望眼欲穿了,彻底解放被元数据和动态代码束缚已久的生产力。

首先,要增强T4模板,使之更方便地引用自身和第三方程序集。实现像Razor那种语法支持应该不过分吧。使用好T4模板,可以大大提高代码重用性(对AVL树和红黑树的个人理解),还有避免元数据操作(性能相差7千倍的ToString方法)。

对于一个项目,应该提供一个编译选项,可以自动生成强类型的元数据程序集。比如MVC中,可以这样用:

using MySite.Metadata;  //引入自动生成的元数据程序集
namespace MySite.Controllers
{
public class HomeController : Controller
{
public ActionResult Home()
{
if (!User.Identity.IsAuthenticated)
return Views.Login; //Views自动生成,取代 View("Login")
return View();
}
}
}

假设有一个Person类,有Name/Sex/Birthday三个属性,我们希望这样运行时加一个Age属性:

MyProject.Metadata.Class.Person.CreateProperty("Age", p=> (DateTime.Now - p.Birthday).Year);

调用这些动态属性时,只要用dynamc特性即可(当前这个特性应用很有限),最好能为dynamic类型提供一个类似JQuery的attr函数。 如果能实现JS的eval函数的功能就更好了,那样C#代码也许会变得我都不认识了。

三、设计面向

编程语言发展已经超过半个世纪了,先是面向变量的汇编语言,高级语言出现后,从Pascal/C语言面向过程和变量,到C++以后的面向对象。 C#和Java只是语言特性上有大幅改进,设计思想并没有飞跃。

C#作为最为先进的编程语言,反映了当前语言发展的瓶颈。要有所突破,必须要有新的设计思想,把面向粒度提高到新的层次。

个人分析后认为,未来C#或C#的后继者,会向三个方向发展:

1. 面向集合

未来编程语言遇到的业务逻辑将更复杂,对集合处理是业务逻辑的核心内容。LINQ使C#走在业界的前列,然而还有许多问题。

由于历史原因,集合类型太多太乱。支持泛型是必须,我们需要根据可变性、排序性、Hash特性、并发要求等,使用一致的高性能集合类型。这些集合类能够灵活转化,智能地处理扩容、复制等底层操作,且没有LINQ那样无法跨程序域传递的限制。这需要框架和CLR双重支持。

2. 面向并发

这个是很自然的方向,除非出现光、生物、量子计算技术的飞跃,不然半导体电路处理器单核极限愈来愈难突破,多核趋势愈演愈烈。未来的编程语言,并发支持必须融入其底层。

还是拿Node.js来说,已经初具此特性,其对IO的访问全部非阻塞的,是从底层支持的异步操作。

对于C#来说,就不只是框架上修修补补,而是CLR的全面支持。async和await出现是个很好的苗头,期待看到更多这样的发展。

3. 面向任务

Node.js它通过事件轮询(event loop)来实现并行操作,这只能处理最简单地多任务同步。要实现真正的并发语言,并满足日益复杂的业务逻辑处理,必须对并发的单元-任务进行有力的支持。

.NET对任务有了System.Threading.Tasks下一系列类的支持,但这只是开始。我们需要动态地创建、分解、修改、取消任务,需要方便地获取和控制任务的状态,管理超时和资源,统计任务效率,处理异常。

前面的路还很远,很长,也一定很精彩。以后我还会继续研究这些方向。

四、平台支持

M#既然能开发操作系统,那定是能编译成Native Code。其实C#本来早就可以有这个功能了,把编译器和NGEN结合一下就行了。但我倒觉得即使有也不没有什么激动人心的,毕竟操作系统才几个?接触的人屈指可数。何况微软一个新操作系统未来能赢得多少市场也未敢期望太高。重要一百倍的平台支持,我认为是各种浏览器IE/FF/Chrome,或者三大浏览器引擎。

其次,至少微软自家的产品IE应该支持,还有SQL Server/Office这些重量级产品,不支持实在说不过去。

我曾经以为Javascript会在数年被淘汰,然而现在都开始逆袭Server端了。如果C#开发的程序能直接在各种浏览器上运行,C#才真正迎来了春天。

上一篇:POJ 2352


下一篇:c# System.Object类和数据的安全转型