`
RednaxelaFX
  • 浏览: 3017655 次
  • 性别: Icon_minigender_1
  • 来自: 海外
社区版块
存档分类
最新评论

装上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模式的时候会方便很多。可以关注一下这个特性以后的使用状况。
2
0
分享到:
评论
9 楼 cajon 2008-10-30  
RednaxelaFX 写道

cajon 写道我的理解是说:“如果一个方法调用中包含了动态对象,那么这个对象的实际类型将会参与到分发的推断中。”还是说:“只要一个方法调用中包含了动态对象,这个方法就会严格的按照多分发进行分发。也就是说,所有参数的类型都参与分发的推断。”在你的另外一篇Blog中说“一个表达式中任何一个值的类型是dynamic的时候整个表达式的类型都是dynamic……”,是不是指的这个问题?

嗯,是后者:无论一个方法调用中哪些对象是dynamic类型的哪些不是,整个方法调用中涉及的所有参数的实际类型都要参与到方法分发的判断中。另外开了帖来说明这个问题:http://rednaxelafx.iteye.com/blog/260206

呵呵,不知为何,刚才没有看到你的帖子,刷新一下才出来。
你的新帖子写的很详细,谢谢。
8 楼 cajon 2008-10-30  
Colorful 写道

在 .NET 4.0 中,俺唯一关注的是它的并行库,其它的没有兴趣,也不需要花费太多精力研究,呵呵。

就目前所见到的 CTP 代码来看,并行库功能太少。
看起来像是一个高级线程池的扩展。

而且很重要的一点是这些未来语言特性几乎都是性能杀手。
特性太多,也会导致门槛比较高,不利于初学者。
C++ 被很多人不喜欢的原因之一啊。

呵呵,是啊。但是,我相信动态特性还是有一些挖掘的空间的。毕竟大多数应用中,这里的性能都不是问题。
另外,我非常喜欢那个“编译器是服务”的概念。
7 楼 RednaxelaFX 2008-10-30  
cajon 写道
我的理解是说:“如果一个方法调用中包含了动态对象,那么这个对象的实际类型将会参与到分发的推断中。”还是说:“只要一个方法调用中包含了动态对象,这个方法就会严格的按照多分发进行分发。也就是说,所有参数的类型都参与分发的推断。”在你的另外一篇Blog中说“一个表达式中任何一个值的类型是dynamic的时候整个表达式的类型都是dynamic……”,是不是指的这个问题?

嗯,是后者:无论一个方法调用中哪些对象是dynamic类型的哪些不是,整个方法调用中涉及的所有参数的实际类型都要参与到方法分发的判断中。另外开了帖来说明这个问题:http://rednaxelafx.iteye.com/blog/260206
6 楼 RednaxelaFX 2008-10-30  
Colorful 写道

在 .NET 4.0 中,俺唯一关注的是它的并行库,其它的没有兴趣,也不需要花费太多精力研究,呵呵。 就目前所见到的 CTP 代码来看,并行库功能太少。 看起来像是一个高级线程池的扩展。 而且很重要的一点是这些未来语言特性几乎都是性能杀手。 特性太多,也会导致门槛比较高,不利于初学者。 C++ 被很多人不喜欢的原因之一啊。

Hmm...我觉得.NET 4的并行扩展还是很有点意思的,至少比没有好多了(汗
PLINQ和TPL乍一看确实是像高级线程池的扩展,但重要的是使用它们的时候,程序员所采用的精神模型与直接使用线程还是有区别的。CCR方面则远不只是线程池那么简单,而是整套基于消息传递的actor模型的并行库。

特性多不等价于门槛高。要看这些特性是如何设计,如何分布到语言当中的。
Make simple things simple, hard things possible.
Python和Ruby等现在流行的脚本语言的一个重要卖点就是门槛低。但它们都不缺乏高级功能,事实上它们的高级功能比现在的C#要更多更强大。像Rails那样大量使用元编程技巧的库,初学者能吃透么?即便不理解内在的机制,初学者仍然可以使用Rails来完成简单的工作。也就是simple things simple。
性能方面,“对运行速度有高要求”本身就是一件困难的事,有内在的复杂性。如果做一件事情无论是否特别追求运行速度都必须写同样繁琐的代码,那就违背simple things simple的精神了。如果需要追求速度的时候没办法去做,那就缺乏hard things possible的能力。
我觉得C# 3/LINQ就能体现simple things simple, hard thigns possible的精神。首先是精神模型:假设需要根据条件对一组数据过滤,那么“一组数据”和“过滤”就是问题的基本概念,属于本质复杂度。于是用LINQ很方便的就能做到这个功能:
from item in list
where verifyCondition( item )
select item

这段代码准确的映射到了基本概念上:一组数据IEnumerable<T>/IQueryable<T>,过滤where。Simple things simple。
但如果要快,那问题本身就有了更高的复杂度。使用简单的LINQ既然不能满足要求,那就换回使用C#更基本的元素来解决问题就是。Hard things possible。
抱怨C#或任何语言复杂的人,应该看看自己抱怨的到底是问题本身的复杂度(essential complexity)语言带来的复杂度(accidental complexity)。抱怨的是前者只能说明自己不胜任这个工作;抱怨的是后者则会推动语言的发展——要么既有语言会试图降低特定问题的复杂度,要么会出现新语言替代既有语言。

要是没有宏没有模板的话,C++还是只很乖巧的小猫的……||| 当然那也就不是C++了。
5 楼 Colorful 2008-10-30  
在 .NET 4.0 中,俺唯一关注的是它的并行库,其它的没有兴趣,也不需要花费太多精力研究,呵呵。

就目前所见到的 CTP 代码来看,并行库功能太少。
看起来像是一个高级线程池的扩展。

而且很重要的一点是这些未来语言特性几乎都是性能杀手。
特性太多,也会导致门槛比较高,不利于初学者。
C++ 被很多人不喜欢的原因之一啊。
4 楼 black.angel 2008-10-30  
75个G!!!!        
3 楼 cajon 2008-10-30  
呵呵,关于最后一段“单一分发”和“多分发”的部分没有太看明白。

我的理解是说:“如果一个方法调用中包含了动态对象,那么这个对象的实际类型将会参与到分发的推断中。”还是说:“只要一个方法调用中包含了动态对象,这个方法就会严格的按照多分发进行分发。也就是说,所有参数的类型都参与分发的推断。”

在你的另外一篇Blog中说“一个表达式中任何一个值的类型是dynamic的时候整个表达式的类型都是dynamic……”,是不是指的这个问题?

2 楼 RednaxelaFX 2008-10-29  
如果是以“云计算”为背景的话,平台间的互操作理论上是很容易的,反正都是用Atom、JSON等格式以REST风格的API提供服务。不过现实总没那么美好就是了。
(可以的话我真不想用“云计算”这个词……)

我觉得技术发展得快并不可怕,关键是学习的时候要掌握思想而不是停留在表面的API上。最近看的一些访谈里看到好多大牛都做过许多不同的工作,有的可能相关性很小,但他们照样很快掌握了;要是技术发展很可怕的话,他们都是怎么过来的。

1 楼 pignut_wang 2008-10-29  
微软的步伐太快了,现在java和.net互通已经成为了焦点,可惜java对很多标准支持的比较慢,微软对标准支持的也不完全,真是困难重重,真不知道程序员的未来在何方

相关推荐

Global site tag (gtag.js) - Google Analytics