装上VS2010 CTP,随便记点什么

相关链接:
Visual Studio 2010及C# 4.0的预览版资源链接
The Visual Studio 2010 and .NET Framework 4.0 CTP FAQ

呼,终于下决心装上了。我可怜的笔记本。VPC2007的supported system里居然没有Vista Home Premium,装VPC2007SP1时弹出个警告窗口吓了我一跳。后来发觉那警告只是说“不支持”,没说“不让装”或者“不能用”,于是照样装。

那个VPC镜像解压出来之后并不是一开始就有75G那么大。根据FAQ,安装的最小硬盘剩余空间是40G,最好是有75G。分配给虚拟机的内存需要有1024M,我的机器就只有2G内存,初次启动的时候居然失败了,说宿主操作系统没有足够内存 T T……还好关了几个后台服务之后勉强满足了内存需求然后启动了虚拟机。实际运行起来还挺顺畅的。至少开着几个IE都没有卡。说真的用这个虚拟机比用host的Vista舒服……决定了,这段时间开新笔记本的时候就直接进虚拟机了。

现在我就正在这个镜像所附带的Windows Server 2008 Standard上在写这帖。然而刚才看了FAQ之后才发觉不应该那这个虚拟机镜像上网的 OTL
FAQ说这个镜像里的评估版软件给出的激活提示都可以无视,包括Windows Server 2008要求激活的提示。于是刚才我选了忽略,但不知道16天后会怎样呢 -_-

===========================================================================

Anders Hejlsberg在PDC 2008的The Future of C#演讲跟他先前在JAOO2008上的演讲非常相似——前几张演示稿都是一样的。看JAOO的演讲时我超激动,这次则平静了很多……但还是有震惊的部分。直接把JavaScript代码复制到C#源文件里,简单修改后就能直接运行的能力真是有意思,duck typing的演示虽然预见到了但实际看到运行的状况还是很有趣;更有趣的是Anders演示的REPL能力,虽然Mono在这部分已经领先了( CSharpRepl)。可惜Compiler as a Service的功能到底什么时候能推出,是否能赶上.NET 4/C# 4都还是未知数;多半是要等到C# vNextNext了 -_-|||
Anders一直在说编程语言的趋势有三点:declarative、dynamic、concurrent。而C# 4的主题就是dynamic的部分;concurrent部分则由.NET Framework来提供,等相关功能更加成熟的时候,或许会考虑将这些功能加入到C#的语法中。

===========================================================================

.NET Framework 4.0的更新:

大家特别关注的是PLINQ、CCR等与并行处理相关的内容。这部分……需要花点时间来看,回头再说。DLR相关的部分跟我预期的差不多。

System.dll:
增加了System.Numerics命名空间,里面公开的类型有一个:BigInteger。以前一直有人抱怨微软不在标准库里提供BigInteger的功能,这回从算有了。实际上,这个命名空间并不是新增的,只不过是从3.5里的System.Core.dll中internal的System.Numeric移动过来而已。

System.Core.dll:
许多东西都大幅度更新了,包括System.Linq.Expressions命名空间里新增的语句树的支持,System.Scripting等与脚本语言相关的支持,等等。
有趣的是这个程序集里新增加里Microsoft.CSharp、Microsoft.CSharp.Semantics、Microsoft.CSharp.Syntax等一些非空开命名空间,里面的内容就是……一个完整的C#编译器!Eric Lippert之前提到过他们在用C#来写C#编译器,原来这个工作就是指.NET 4里的C# 4编译器么。有意思。不知道这些API有没有机会暴露更多出来呢。
另外还有一组新增的API也相当有趣:System.Shell.CommandLine命名空间。提供了十分方便的命令行解析的功能。

===========================================================================

C# 4.0的一些小实验

刚才在C# Future的论坛看到NyaRuRu发的一帖: Ambiguity with variant generics/ Variance Ambiguity,于是写了相似的代码用这次CTP里的C# 4.0编译器测了一下:
using System;
using System.Text.RegularExpressions;

public interface ICountable<out T>  {
    int Count { get; }
}

public class MyCollection : ICountable<string>, ICountable<Regex>, ICountable<Match> {
    int ICountable<Regex>.Count {
        get { return 1; }
    }

    int ICountable<string>.Count {
        get { return 2; }
    }

    int ICountable<Match>.Count {
        get { return 3; }
    }
}

public static class Program { 
    static void Main( string[ ] args ) {
        var col = new MyCollection( );
        ICountable<object> countable = col;
        Console.WriteLine( countable.Count );
    }
}

编译能通过,运行结果是2。一开始让人挺摸不着脑的,再试了一下发现这里实际选取了哪个版本的ICountable<out T>.Count取决于MyCollection声明其实现的接口的顺序。如果把ICountable<Regex>写在第一位的话,运行结果就会是1。这真是太诡异了,然而这并不是C# 4自身就能解决的问题,而是涉及到CLR的类型系统。
这段代码在C# 3或以前的版本里自然是编译不了。如果把ICountable<out T>的out去掉并在Main的代码里做强制类型转换(ICountable<object>)(object)col,那么在C# 3可以编译通过,但在.NET Framework 3.5上运行会得到运行时异常: System.InvalidCastException,无法将类型为“MyCollection”的对象强制转换为类型“ICountable<object>”。
看了看生成出来的MSIL,除了ICountable<out T>写为ICountable<+T>外,其它都跟C# 3编译出来的一样。差异就在这里了。把C# 3编译出来的版本用ildasm解成MSIL,手工添加上variance标记(那个加号),再用ilasm编译回exe,就能看到.NET Framework 3.5上也能运行该代码并得到与C# 4版本同样的结果。事实上variance的功能在CLR里一早就存在了,只是C#在4之前一直没暴露这个功能而已。MSR的Andrew Kennedy写过一篇 相关的论文,不知道最终.NET 4会不会选择修改类型系统来处理这个问题呢?还是说C# 4的编译器会做些处理?只能等了。


然后看看C# 4的动态特性。借助 C# FutureIDynamicObject Example里实现的Dynamic类,可以写出这样的代码:
using System;
using System.Collections.Generic;
using System.Scripting.Actions;

class NameValuePair {
    public string Name  { get; set; }
    public object Value { get; set; }
}

// a custom dynamic lookup implementation
class PropertyBag : Dynamic {
    Dictionary<string, object> _items;

    public PropertyBag( ) {
        _items = new Dictionary<string, object>( );
    }

    public override object GetMember( GetMemberAction action ) {
        return _items[ action.Name ];
    }

    public override void SetMember( SetMemberAction action, object value ) {
        _items[ action.Name ] = value;
    }
}

class DuckTyping {
    static void Main( string[ ] args ) {
        // plain C# object, statically typed
        var pair = new NameValuePair {
            Name = "Plain Old C# Object",
            Value = "The Value"
        };
        PrintNameValue( pair );

        // custom dynamic object, statically typed to be "dyanmic"
        dynamic props = new PropertyBag( );
        props.Name = "Property Bag Instance";
        props.Value = "The Value Property";
        PrintNameValue( props );

        // anonymous type object
        var anoTypeObj = new {
            Name = "Anonymous Type Instance",
            Value = "Another Value"
        };
        PrintNameValue( anoTypeObj );
    }

    // duck typing
    static void PrintNameValue( dynamic obj ) {
        Console.WriteLine( "Name:  {0}", obj.Name );
        Console.WriteLine( "Value: {0}", obj.Value );
    }
}


可以看到PrintNameValue()这个方法的参数被声明为dynamic类型的,于是这个方法实际上就用到了Python、Ruby社区里流行的duck typing:只要一个对象有名为Name和Value的成员,PrintNameValue()就能应用到该对象上,无论是普通的.NET类型(NameValuePair)、匿名类型、还是实现了IDynamicObject的“动态类型”(PropertyBag),都没问题。
(Anders和Jim做的演示里都用到了System.Dynamic.DynamicObject类,但CTP里这个类并不存在。怪哉,CTP还是不够新啊。还好这个类可以从C# Future获得,也可以直接从DLR源码中获得(IronRuby里,System.Scripting.Actions中的Dynamic类))

然而这次的CTP里的C#编译器似乎并没有对CallSite对象的创建做多少优化,生成的代码看起来还有很大的改进空间。想了一下,刚才觉得可以优化的一个地方看来是不适合做静态优化,还是像现在这样每个调用点都创建一个CallSite对象来得好些。

使用了动态类型的方法调用有一个非常非常重要的特性,很可能会被人忽略:方法的分发从单一分发(single-dispatch)变成了多分发(multi-dispatch)。举例来说,假如有这么一组类:
public class A { }
public class B : A { }

public class Foo {
    public virtual void Bar( A a ) { }
    public virtual void Bar( B b ) { }
}

public class Goo : Foo {
    public override void Bar( A a ) { }
    public override void Bar( B b ) { }
}

那么使用dynamic与否就会带来区别:
class Program {
    static void Main( string[ ] args ) {
        // plain old single dispatch
        Foo goo = new Goo( );
        A b = new B( );
        goo.Bar( b ); // calls Goo.Bar( A )

        // multi-dispatch
        dynamic b1 = b;
        goo.Bar( b1 ); // calls Goo.Bar( B )
    }
}

这个例子里两次对Bar()的调用都用的是Goo上的版本体现出了方法分发的效果。

单一分发:方法调用会根据第一个参数的实际类型(而不是变量声明的类型)来决定选用的版本。
多分发:所有参数的实际类型都是分发的判断条件。

原本在C#里,成员方法都有一个隐式参数this作为第一个参数,而分发也是针对this来进行的。现在有了动态类型支持,动态方法调用的分发就变成了多分发。
有了这个特性,在实现Visitor模式的时候会方便很多。可以关注一下这个特性以后的使用状况。

你可能感兴趣的:(C++,c,C#,Microsoft,LINQ)