摘要: 上一篇博客,我也掉到了首页之争中去了。这一篇,我就介绍一个可能替代博客园的社区。  阅读全文
posted @ 2009-04-17 13:03 Colin Han 阅读(3737) | 评论 (34)编辑
     摘要: 我设想中的一个可以让我搬家的社区。  阅读全文
posted @ 2009-04-16 21:48 Colin Han 阅读(573) | 评论 (7)编辑

标题党一把。

博客园的blog很久没有更新了。自从博客园取消了全文输出之后,我就有离开博客园的想法了。博客园作为一个公共空间,其中的一些做法虽然我不认同,但是我也认为无可厚非。毕竟谁的地盘谁做主。但是,博客园的做法确实伤害到我(作为一个博客作者)的利益。

想离开博客园,于是就在想去哪里?放眼望去,国内还没有一个网站能够代替博客园。于是顺着这个思路想下去,谁来代替博客园呢?自我感觉有了一些想法,发出来。虽然标题看起来刺目。但是,核心,还是希望从另外一个方面为博客园提些建议。

这是第一篇,先给大家(各位博客作者)一些发布BLOG的建议,以帮助大家的文章更多的被人发现和浏览,也让读者更容易的发现感兴趣的文章。因为,我觉的,作为一个博客作者,写出来的东西被更多的人看才是博客的核心价值。

首先要说一下最近浏览博客园首页给我的感受:

1. 文章量很大

平均一天都会有几十篇文章到首页上,不客气的说,每天在Google Reader中浏览博客园首页的RSS是一件艰巨的任务。

2. 涉及范围广

应该说博客园首页的文章涉及了.NET开发的方方面面。有时候还偶尔出现一些其它平台的文章,例如:GAE和JAVA。

3. 文章深度不等

有一些很有深度的文章,也有一些入门级的文章,有一些做程序的文章,也有一些做人的文章。

我从来不主动上博客园,我大多时候都会从Google Reader中浏览博客园首页的文章。除了订阅首页外,我还会订阅一些我比较感兴趣的博主的RSS,比如:TerryLee, JeeseZhao等。对于他们的文章,我都会投入更多的精力关注。而首页的文章,我只能很粗略的浏览。

Google Reader为我们提供了很好的快捷键,我可以连续的按"J"键,快速的浏览文章。因此,基本上每篇文章,我都仅看文章标题的前几个字

呵呵,说的正题了。文章多,范围广,层次不等。最大的结果就是读者无法投入太多的精力给每一篇文章。Dudu一定也意识到这个问题,也一定在思考怎样解决这个问题。接下来的文章中,我会用另一种方式给出我的建议。

这里先给各位看官提一些建议,帮助大家提高自己文章的阅读量:

1. 文章对大家有用

这一条等于没说。但是,并不是每个人在发布博客之前好好想过这一条。最近几次发生在博客园里的骂仗也都是因为这一点而触发的。

其实,下面所有的技巧,如果没有这一条,都是白搭

发布前想一想,如果不确定对大家有用,那还是不要发布在首页上了。在自己的首页上发布就好了。如果你的博客写的好,会有人关注的。

2. 写好标题,尤其是前几个字

文章好,标题一定要好,否则,很难被大家注意到。很多时候,标题党一把也无妨。这里尤其要注意标题的前几个字。如果能将你的文章的精华浓缩在前几个字上,那就是最好的了。这样,更利于关注该主题的人发现你的文章。比如:我最近对于“并行计算”,“.NET 4.0”就很感兴趣。如果你将这些关键字放在了文章的后面,那我很可能就会忽略掉你的文章。

3. 写系列文章,并且为整个系列起一个好名字

整个系列的文章无论对于SEO还是首页来的访问量都会有好处。如果可能,做一些规划,写整个系列的文章。对于访问量会很有好处。如果能够为系列起一个好的名字,就更好了。另外,最好将系列标题放在文章标题的前面。

很多时候,好的系列文章会让我主动订阅你的博客(RSS)。即使没有订阅,你的系列标题也会成为我所关注的关键字,这当然就需要你将系列标题放在文章标题的前面了。

4. 为系列文章建立目录页

最好能够为你的系列文章专门建立一个目录页,并且每个文章的前面都有到目录的链接。这样,如果我忽略了你的第一片文章,还可以很容易的在你的系列文章中跳转。

时刻要记者,搜索引擎也是你的文章读者的一个重要来源。建立目录会帮助搜索引擎来的读者在

5. 注意你的格式

我在博客园转了很很久了,从一个.NET菜鸟转成老鸟。我发现就有一些作者,文章的内容不知道怎样(因为,我一般都看不完就放弃了),格式是乱的一塌糊涂。如果你真的想让博客成为你的名片。多在排版上下点功夫还是值得的。

最差情况下,发布后,自己浏览一遍,看看自己恶心不。

其实,排版的事情很简单,往往仅仅加几个空行,设几个粗体字就够了。最好不要搞太多花哨的东西。当然,代码还是有语法高亮好一些。

6. 斟酌你的摘要

我对博客园强制摘要输出意见非常大。但是,意见归意见,如果要在博客园做窝,不得不摘要输出啊。虽然,为文章写一个好的摘要是一件很费劲的工作。但是,对你的访问量会有很大好处的。

7. 选择正确的发布时间

如果你如“老赵”等老鸟,有一帮抢沙发的粉丝。什么时间发贴不重要。但是,对于大多数如我一般的作者,必要的时候,还是选择一下发布时间为好。最好在工作日的下午。那样可以为你的文章带来更高的曝光率。

其实,本条是有点邪恶的说。首先,文章质量还是最重要的。如果大家都来掐时间发贴,只会是大家都没有好处得。但是,世上还是懒人多。一分耕耘,一分收获嘛。

8. 偶尔发布一些感性的文章

博客和正规出版物的不同就是他更关注个人。偶尔发布一点感性的文章会帮助别人更全面的了解你。从而为你赢得一些订阅。但是,一定不能往首页上发的。那只会导致骂仗。

记住,订阅用户才是最有价值的读者。为他们,付出再多都值得。

9. 最后一条,申请自己的域名

如果你真的将博客作为自己的名片,申请独立的域名还是很有好处的。毕竟,自己的地盘自己做主。想“全文”全文,想“摘要”摘要。如果你想知道怎样低成本的建立一个独立域名的Blog,可以参考一下我的这篇博客。我现在正在尝试中,随时会将实际尝试的结果公布出来。当然,这个就不能再发布到首页了,你要是有兴趣,可以订阅我的博客

如果,钱对于你不是问题,就不要参考我的文章了,GFW很强大,我们很弱小。

posted @ 2009-04-16 13:05 Colin Han 阅读(3127) | 评论 (37)编辑
怀旧的感觉

 

posted @ 2008-11-16 12:32 Colin Han 阅读(494) | 评论 (1)编辑

今天编写单元测试的时候,出现一个奇怪的错误信息:

Test Run deployment issue: The location of the file or directory
'e:\********\bin\debug\ComponentModel.dll' is not trusted.

网上搜了一下,说将你的Dll所在的目录设为FullTrust。但是,我就奇怪了,我的本地文件都是FullTrust的啊,为什么就唯独这一个文件无法使用呢?

只好继续Google了,终于让我找到了这篇文章。其中James Fuhr说什么Block,Unblock的东东,让我很是不理解。最后终于在文件的属性对话框中找到了这个按钮。郁闷啊,藏的还真是隐蔽。

 

贴个图,留念。想来对你也有用

posted @ 2008-10-20 17:25 Colin Han 阅读(374) | 评论 (3)编辑
     摘要:

IronPython 2.0完全基于微软DLR平台实现的。并且提供了良好的和.NET CLR对象之间交互的能力。在本系列文章里,我们将尝试实现一个自定义控件,使得你可以象使用标准Python控制台一样在其中输入Python代码,并且运行。

当然,为了能够让IronPython很好的操作CLR对象,其中还是有很多技巧,让你的CLR对象对IronPython更友好,这一节,我们就要使用ExtensionTypeAttribute为已有的CLR对象添加DLR友好性支持。

  阅读全文
posted @ 2008-10-06 10:08 Colin Han 阅读(2037) | 评论 (9)编辑
     摘要: IronPython 2.0完全基于微软DLR平台实现的。并且提供了良好的和.NET CLR对象之间交互的能力。在本系列文章里,我们将尝试实现一个自定义控件,使得你可以象使用标准Python控制台一样在其中输入Python代码,并且运行。 当然,为了能够让IronPython很好的操作CLR对象,其中还是有很多技巧,让你的CLR对象对IronPython更友好,这一节,我们就要实现一个集合对象,并且让这个集合类可以向IronPython的内置序列类型一样的支持切片操作。  阅读全文
posted @ 2008-08-25 10:32 Colin Han 阅读(1775) | 评论 (4)编辑

动态类型语言(以下简称:"动态语言"),在10年前就已流行起来。JavaScript更是成为了WEB前台开发的事实标准。但它们进入普通开发 人员的视野也就在近几年。随着Web2.0和敏捷开发方法论的兴起,动态语言的灵活高效的特性成为了它被更多项目选择和使用的理由。一些大型网站已开始使 用动态语言来实现,其中,国内比较优秀的作品有“豆瓣”。微软更是不甘落后,建立了DLR(动态语言运行时)来吸引动态语言爱好者在其上实现动态语言。IronPython就是其主要成员之一。

在本系列文章中,我们将逐步实现一个自定义控件,实现类似IDE的Immediate窗口的功能。用户可以在其中输入和运行IronPython代码。 【返回目录


上一节中, 实现自定义模块的尝试失败了。后来仔细想想,也许有了clr module,以及IronPython在CLR对象的封装上实现了很多对IronPython兼容特性(呵呵,我想这个就可以做一个专题讨论)。我们大多时候已经可以将CLR对象当作IronPython对象一样操作了。也许这就是为什么IronPython不打算将PythonModuleAttribute提供给我们用的原因。谁知道呢,也许微软提供了途径,我没有找到。

IronPython在对CLR对象进行封装时,已经进行了很多兼容方面的考虑。但是,有些东西,IronPython仅仅提供了方案。真正的实现还是要我们自己来了。

比如:让一个CLR对象支持动态类型。即运行时添加删除属性和方法。

大家知道,对于静态类型语言,一个对象的类型在它被创建时就被确定下来,并且不能被改变。而一个类型具有哪些成员也是在编译时被确定下来的。因此,下面的代码在编译时就会报错。

 1public class Foo
 2{
 3    public int B
ar getset; }
 4
 5    public static void Main()
 6    {
 7        Foo foo = new Foo();
 8        foo.xxx = 10; // 这一行编译失败
 9    }

10}

而对于动态类型语言,类似上面的代码就完全是合法的代码。对于大多数习惯了C#这样的强类型语言的开发人员(包括我自己)可能都觉得这样的规定除了增加出错概率外,没有任何意义。但是,这样的规定配合一些其它功能(比较有名的就是鸭子接口),这样的设计反而可以发挥出来巨大的优势。好的,我们不来讨论哪种语言更好,仅仅给出上面代码的IronPython版本。

1class Foo:
2    Bar = 0
3
4foo = Foo()
5foo.xxx = 10

呵呵,Python确实比C#精炼

如果使用我们的DLConsole,你会发现对于我们植入的对象(比如:Button1和TextBox1),下面的代码就会产生一个MissingMemberException('Button' object has no attribute 'xxx')。

Button1.xxx = 10

先让我们从头开始实现一个类型,让你可以在其中添加和删除成员。代码如下:

 1 public class DLRFriendlyObject
 2 {
 3     Dictionary<stringobject> _dict = new Dictionary<stringobject>();
 4 
 5     // 呵呵,这个属性就永远都不能被IronPython访问了。
 6     public string Foo { get { return "this should not be returned"; } }
 7 
 8     [SpecialName]
 9     public object GetCustomMember(string name)
10     {
11         if (name == "_dict")
12             return _dict;
13         else 
14             return _dict[name];
15     }
16 
17     [SpecialName]
18     public void SetMember(string name, object value)
19     {
20         _dict[name] = value;
21     }
22 
23     [SpecialName]
24     public void DeleteMember(string name)
25     {
26         _dict.Remove(name);
27     }
28 
29     [SpecialName]
30     public IEnumerable<string> GetMemberNames()
31     {
32         return _dict.Keys;
33     }
34 }

注:因为这个类型和DLConsole没有直接关系,因此,上面的代码在TestDynamicLanguageConsole工程中。

上面的代码中,出现了一个比较特别的Attribute [SpecialName],它被定义在“System.Runtime.CompilerServices”命名空间下,也就是说,它并不是DLR定义的Attribute。查了一下MSDN,发现“.NET Framework 中目前不使用 SpecialNameAttribute 类,但该类被保留以备将来之用。”。呵呵,看来微软早就留了一手。

这一节中添加的几个Special的方法,都添加了这个Attribute。你会发现,随后的几节中,你随时都会发现这个Attribute的身影。如果你不添加这个Attribute,IronPython都会将它们当作普通成员处理。

除此之外,就是四个固定名称的方法:GetCustomMember, SetMember, DeleteMember和GetMemberNames。实现这些方法,使用一个标准的Dictionary储存这些属性就可以了。现在,你就可以在IronPython中象操作动态类型对象一样的操作这个对象了。

为了简单,我的演示程序中直接将该对象注册到Scope中了。你可以使用第二讲中的方法,通过clr模块从头构建这个对象。

下面是运行效果图


但是,实现这几个方法后,一个最直接的影响就是IronPython默认实现的属性读取和调用方法都失效了。也就是如果你直接访问Friend.Foo属性将会收到一个KeyNotFoundException(The given key was not present in the dictionary.)。因此,你需要对原有的属性和方法进行一些处理。方式可以类似上面代码中关于“_dict”的处理。

下一节,我们将会实现一个Collection对象,让它能够支持IronPython的切片操作和列表解析。敬请关注feedsky

大家可以从这里下载可运行的源代码。

免责声明:本系列文章,完全是我个人研读IronPython源代 码后找到的实现方案,并未详细的研究过IronPython的相关官方文档。因此,并不保证符合微软DLR和IronPython的设计思路,亦不能保证 在DLR和IronPython 2.0正式发布后能够继续使用。 

posted @ 2008-08-18 11:59 Colin Han 阅读(2003) | 评论 (6)编辑


失败

在IronPython的源代码中,提供了一个PythonModuleAttribute,我原以为这个Attribute是为自定义Module建立的。在clr.AddReference时会检查Assembly中的所有PythonModuleAttribute。并将指定的类型作为Module导入到Python的运行环境中。

但是,今天实际测试的结果并不是这样。IronPython仅在自己的IronPython.dll和IronPython.Modules.dll中支持这个Attribute.

目前看来,向Scope中添加Clr对象还是比较正统的实现方式。关于其他的扩展途径,还正在研究中。

跳过这一节,下一节《使CLR对象对动态语言更友好(一)》中,我将实现一个CLR对象,可以支持最基本的动态语言特性——运行时添加删除属性。

posted @ 2008-08-16 17:24 Colin Han 阅读(396) | 评论 (0)编辑

动态类型语言(以下简称:"动态语言"),在10年前就已流行起来。JavaScript更是成为了WEB前台开发的事实标准。但它们进入普通开发 人员的视野也就在近几年。随着Web2.0和敏捷开发方法论的兴起,动态语言的灵活高效的特性成为了它被更多项目选择和使用的理由。一些大型网站已开始使 用动态语言来实现,其中,国内比较优秀的作品有“豆瓣”。微软更是不甘落后,建立了DLR(动态语言运行时)来吸引动态语言爱好者在其上实现动态语言。IronPython就是其主要成员之一。

在本系列文章中,我们将逐步实现一个自定义控件,实现类似IDE的Immediate窗口的功能。用户可以在其中输入和运行IronPython代码。 【返回目录


上一节中,我们成功的将CLR对象添加到了IronPython的运行环境中。相信通过上一节的内容。大多数人都已经可以很容易的将IronPython集成到自己的应用程序中。但是,某些时候,我们为了给我们的用户以更好地体验。需要对IronPython进行一些扩展,比如:添加自定义的方法到IronPython环境。

1. 先看运行效果

我在DLConsole中输入如下的脚本:

TextBox1.Text = str(Sum(1025))

运行结果如图:

 

2. 向DLConsole中注册Delegate

之前,已经可以将一个对象注册到ScriptScope中,并且通过它的名字访问这个对象。大多数现代的语言中,都已经能够将方法作为对象传递。.NET是通过Delegate对方法进行的封装和传递的。DLR中也对Delegate提供了很好的支持。因此,我们不需要对DLConsole进行任何修改,就可以完成这个工作。下面的代码是测试工程的代码。

 1namespace TestDynamicLanguageConsole
 2{
 3    public partial class Form1 : Form
 4    {
 5        public Form1()
 6        {
 7            InitializeComponent();
 8
 9            this._dlConsole.Registor(this.button1, "Button1");
10            this._dlConsole.Registor(this.textBox1, "TextBox1");
11            this._dlConsole.Registor(new SumDelegate(Sum), "Sum");
12        }

13
14        public delegate int SumDelegate(int x, int y);
15        public int Sum(int x, int y)
16        {
17            return x + y;
18        }

19    }

20}

在代码的第11行,我们将一个方法注册到DLConsole中,命名为"Sum"。就实现了上面展示的功能。

至此,我们已经可以通过向ScriptScope中注册Delegate的方式,使Python脚本使用我们自定义的方法。但是,你会发现这样的实现方式虽然简便快捷,却无法实现函数的重载。也就是说,你不能针对不同的数据类型注册多个Sum方法。

下一节《使用Module扩展IronPython》中,我们将建立一个自定义模块,在其中,我们可以实现函数的重载。(2008-08-16更新:通过实验,发现我所设想的路线是错误的。您可以继续关注下一篇《使CLR对象对动态语言更友好(一)》。我将实现一个CLR对象,可以支持最基本的动态语言特性——运行时添加删除属性。)敬请关注feedsky

大家可以从这里下载可运行的源代码。

免责声明:本系列文章,完全是我个人研读IronPython源代码后找到的实现方案,并未详细的研究过IronPython的相关官方文档。因此,并不保证符合微软DLR和IronPython的设计思路,亦不能保证 在DLR和IronPython 2.0正式发布后能够继续使用。

posted @ 2008-08-04 10:29 Colin Han 阅读(1643) | 评论 (2)编辑

动态类型语言(以下简称:"动态语言"),在10年前就已流行起来。JavaScript更是成为了WEB前台开发的事实标准。但它们进入普通开发 人员的视野也就在近几年。随着Web2.0和敏捷开发方法论的兴起,动态语言的灵活高效的特性成为了它被更多项目选择和使用的理由。一些大型网站已开始使 用动态语言来实现,其中,国内比较优秀的作品有“豆瓣”。微软更是不甘落后,建立了DLR(动态语言运行时)来吸引动态语言爱好者在其上实现动态语言。IronPython就是其主要成员之一。

在本系列文章中,我们将逐步实现一个自定义控件,实现类似IDE的Immediate窗口的功能。用户可以在其中输入和运行IronPython代码。 【返回目录


上一节中,我们建立了IronPython运行环境,并且在其中成功的运行了“print "hello world"”的命令。正如上一节的讨论中所看到的,大家都很关心如何让IronPython脚本和我们的运行环境交互。在这一节中,我们将会在DLConsole上添加两个方法,实现将运行环境中的Clr对象传递给IronPython脚本使用。

大家可以从这里下载可运行的源代码。

1. 先看运行效果

我在DLConsole中输入如下脚本:

 1import clr
 2clr.AddReference("System.Drawing")
 3clr.AddReference("System.Windows.Forms")
 4
 5from System.Drawing import Color
 6from System.Windows.Forms import FlatStyle
 7
 8Button1.BackColor = Color.Red;
 9Button1.FlatStyle = FlatStyle.Flat
10Button1.Text = "Hello IronPython"

运行结果,如图:

 

2. 确保脚本可以访问CLR对象

首先,我们需要脚本能够成功的访问CLR对象。我在DLConsole上暴露了两个方法。分别是:

 1public partial class DLConsole : UserControl
 2{
 3    public void Registor(object obj, string name)
 4    {
 5        this._scope.SetVariable(name, obj);
 6    }

 7    public void UnRegister(string name)
 8    {
 9        this._scope.RemoveVariable(name);
10    }

11}

在上一讲的源代码中,我们保存了一个ScriptScope对象。用户输入的脚本就是在这个Scope对象上运行的。因此,我们在这里向ScriptScope中添加的变量,就能够被用户输入的脚本所访问了。

在测试程序中,我添加了如下的代码来将对象注册到脚本运行环境中。

 1public partial class Form1 : Form
 2{
 3    public Form1()
 4    {
 5        InitializeComponent();
 6
 7        this._dlConsole.Registor(this.button1, "Button1");
 8        this._dlConsole.Registor(this.textBox1, "TextBox1");
 9    }

10}

这时,我们就可以实现类似“Button1.Text = "Hello IronPython"”和“Button1.BackColor = TextBox1.ForeColor”这样的脚本了。但是,你会发现,如果你输入类似“Button1.BackColor = Color.Red”的脚本,会产生一个“name 'Color' is not defined”的异常。是因为在目前的Scope中无法找到Color的定义引起的。

3. 使用CLR类型

如果需要在IronPython中使用CLR类型,需要完成以下几个步骤:

a) 引入clr对象:这个对象实现了对CLR访问的一些必要的操作。例如:添加引用。
b) 添加引用:通过clr.AddReference方法,你可以使用Assembly的名字作为参数来添加对这个Assembly的引用。IronPython会使用.NET加载Assembly的策略去寻找和加载这个Assembly。
c) 引入变量:通过IronPython的“import”或“from ... import ...”语法,将你需要使用的类型引入当前Scope。

之后,你就可以使用类似“x = Form()”语法构建一个对象或通过类似“Color.Red”的语法访问对象的静态成员。

最后,给一个比较复杂的例子,从中可以理解一下IronPython的语法。

 1import clr
 2clr.AddReference("System.Windows.Forms")
 3
 4from System.Windows.Forms import Form
 5from System.Windows.Forms import Button
 6from System.Windows.Forms import DockStyle
 7
 8form = Form()
 9button = Button()
10button.Text = "http://cajon.cnblogs.com"
11button.Dock = DockStyle.Fill
12form.Controls.Add(button)
13form.ShowDialog()

运行效果:


需要说明一下,因为在控制台上输入的脚本都是在同一个Scope对象上运行的,因此,import语句只需要运行一次就可以了。也就是说,上面的代码执行后,你可以继续使用Form、Button等类型。

4. 总结

微软在DLR和CLR之间交互方面的考虑很多,因此,对一些简单的操作,我们甚至感觉不到CLR对象和一个IronPython对象之间的区别。当然,动态语言的优势即在于它的动态类型系统,这一点和CLR的静态类型系统有很大的差别。因此很多IronPython的特性(例如:动态添加属性到对象上)无法在CLR对象上使用。在后面的章节中,我们将通过一些扩展接口实现更高级的嵌入。

另一方面,将方法注册到动态语言运行环境中也是大家比较关心的一个话题。虽然,通过注册对象到运行环境,已经可以在脚本中访问这些对象的方法。但毕竟不如直接使用方法来的简单。下一节将会详细的讨论相关的实现。敬请关注feedsky

免责声明:本系列文章,完全是我个人研读IronPython源代码后找到的实现方案,并未详细的研究过IronPython的相关官方文档。因此,并不保证符合微软DLR和IronPython的设计思路,亦不能保证 在DLR和IronPython 2.0正式发布后能够继续使用。

posted @ 2008-07-28 09:17 Colin Han 阅读(1470) | 评论 (12)编辑

动态类型语言(以下简称:"动态语言"),在10年前就已流行起来。JavaScript更是成为了WEB前台开发的事实标准。但它们进入普通开发人员的视野也就在近几年。随着Web2.0和敏捷开发方法论的兴起,动态语言的灵活高效的特性成为了它被更多项目选择和使用的理由。一些大型网站已开始使用动态语言来实现,其中,国内比较优秀的作品有“豆瓣”。微软更是不甘落后,建立了DLR(动态语言运行时)来吸引动态语言爱好者在其上实现动态语言。IronPython就是其主要成员之一。

在本系列文章中,我们将逐步实现一个自定义控件,实现类似IDE的Immediate窗口的功能。用户可以在其中输入和运行IronPython代码。 【返回目录



先我们需要建立一个运行环境,并确保能够在其上运行Python脚本。大家可以从这里下载可运行的源代码。

我们首先来看一下运行结果:(提示:目前该程序是通过Ctrl+Enter执行你输入的代码。下面的输出窗口是IDE的Output窗口)

第一个版本运行效果图
点击看大图

其中主要的代码如下:

 1namespace DynamicLanguageConsole
 2{
 3    public partial class DLConsole : UserControl
 4    {
 5        public DLConsole()
 6        {
 7            InitializeComponent();
 8
 9            ScriptRuntimeSetup runtimeSetup = new ScriptRuntimeSetup(true);
10            this._runtime = ScriptRuntime.Create(runtimeSetup);
11            this._engine = this._runtime.GetEngine(typeof(PythonContext));
12            // 你亦可以使用下面的代码获得脚本引擎,但是,下面的方法可能会在未来版本被废弃
13            // this._engine = PythonEngine.CurrentEngine;
14            this._scope = this._engine.CreateScope();
15        }
 
16
17        ScriptRuntime _runtime;
18        ScriptEngine _engine;
19        ScriptScope _scope; 
20
21        public void Exec(string script)
22        {
23            _engine.CreateScriptSourceFromString(script, SourceCodeKind.Statements).Execute(_scope);
24        }
 
25    }

26}

程序中,我们保存了三个局部变量,ScriptRuntim,ScriptEngine和ScriptScope。

脚本运行时(ScriptRuntime):Hosting动态语言的入口。通过这个对象,你可以获得脚本引擎。添加全局变量等。
脚本引擎(ScriptEngine):实现语言特定的脚本功能,例如:编译源代码。
脚本空间(ScriptScope):提供了脚本运行的空间,脚本将会把其中定义的对象和变量等存储与这个空间里。.NET CLR对象也可以通过这个对象和脚本进行对象的共享。在《第三章:添加CLR对象到运行环境》中我们将会使用这个对象。

下面的图也许可以帮助你了解他们之间的关系。

High Level Hosting Object Relation
点击看大图

我们需要做的,就是构造这样三个对象(程序中的10-14行),然后,使用脚本引擎来编译用户输入的源代码,并且让该代码在ScriptScope上运行(程序中的23行)。

好了,仅仅需要这样7行代码,你的应用程序就具有了执行动态语言的能力。接下来,要让控制台控件更象一个标准的Python控制台《第二章:实现IConsole接口》。敬请关注feedsky

免责声明:本系列文章,完全是我个人研读IronPython源代码后找到的实现方案,并未详细的研究过IronPython的相关官方文档。因此,并不保证符合微软DLR和IronPython的设计思路,亦不能保证在DLR和IronPython 2.0正式发布后能够继续使用。

posted @ 2008-07-19 16:24 Colin Han 阅读(1545) | 评论 (6)编辑

动态类型语言(以下简称:"动态语言"),应该说有很古老的历史了,10年前就已经在学术圈内流行起来。JavaScript更是成为了WEB前台开发的事实标准。但是他们进入普通开发人员的视野也就是在最近几年。随着Web 2.0和敏捷开发方法论的兴起。动态语言的灵活高效成为了他被大多数项目选择和使用的理由。一些大型的项目和网站都开始使用动态类型语言实现,其中,国内比较优秀的作品有“豆瓣”。各个大公司也纷纷加入其中。不断的推进着动态语言的发展。其中最典型的就是GooglePython语言的推崇。

最近Google推出了App Engine平台,为广大的开发人员提供了一个低成本,高扩展性的实现平台。关于App Engine的详细信息,后面我有时间的时候,考虑介绍一下。现在大家可以上网搜索一下。有很多详细的介绍。

推动动态语言发展的并不仅限于Google一家,IBM, Sun等公司也有相应的举措。微软,当然也不会落后,推出了他自己的动态语言平台——DLR 并且在其上实现了IronPython, IronRuby和JavaScript(其中,前两个应该算是社区作品,并且是开源的。最后一个是微软自己的实现,并且,目前还没有看到开源的说)。

目前我找不到DLR的源代码的独立下载地址,大家只能通过下载IronPython或IronRuby的源代码来获得DLR的源代码。简单来说,DLR就像.NET的CLR一样为动态语言提供了一套公共的运行时支持(例如:解释器,GC,语法树以及和CLR的交互等)。用微软官方的说法:DLR使动态语言开发者能够将精力放在该语言核心的功能上,而不是这些通用的功能。至少动态语言开发者并不再需要重写一套GC。虽然,很多开发人员总喜欢做这些。

微软的DLR使得动态语言开发者能够加少很多工作量,同样对于我们这些希望能够将动态语言嵌入到我们的应用程序中的开发人员也是一种好事。我们可以面向DLR去设计,提供基本的平台。然后,针对各种不同语言的特性进行一些优化,就可以简单的将他们嵌入到我们的运行环境里来。

随后的一系列文章中,我将制作一个自定义WinForm控件。该控件的功能就像一个控制台,通过将这个自定义控件嵌入你的窗口,使用户可以在其中输入代码并执行。大家可以将它想象为IDE中的Immediate窗口。

1. 建立运行环境并运行脚本
2. 实现IConsole接口,重定向输入输出
3. 添加CLR对象到运行环境
4. 添加方法到运行环境
5. 使用Module扩展IronPython (失败的项目,微软没有提供对PythonModuleAttribute的支持)
6. 使CLR对象对动态语言更友好
   6.1 支持运行时添加删除属性
   6.2 支持切片
   6.3 使用ExtensionTypeAttribute
7. 使DLConsole支持其它动态语言
8. 高级话题,建立安全沙箱运行IronPython脚本
9. 高级话题,CLR类型和Python类型之间的映射

你可以在这里下载本系列每个阶段的源代码
本系列中所有示例将基于IronPython 2.0 Beta 3.大家可以通过这里下载IronPython的源代码

posted @ 2008-07-13 15:45 Colin Han 阅读(2049) | 评论 (4)编辑

1. 在WinForm上放置一个TabControl,并设置其Dock属性为Fill。

2. 在其中的一个Tab页上放置一个DateTimePicker控件

你会发现,当你在XP系统下,Resize Form时,DateTimePicker会闪烁。研究了很长时间,没有结果。最终放弃C#和Spy++,使用Google研究了一下 :-) 得出结论如下:

需要为DateTimePicker控件添加WS_EX_COMPOSITED Window Style.如下:

    public class MyDateTimePicker : DateTimePicker
    
{
        
protected override CreateParams CreateParams
        
{
            
get
            
{
                CreateParams ps 
= base.CreateParams;
                ps.ExStyle 
|= NativeMethods.WS_EX_COMPOSITED /*0x2000000*/;
                
return ps;
            }

        }

    }

这个Style仅仅被Window XP以上系统支持。功能是将Control的所有画法使用DoubleBuffer优化。(ControlStyles.OptimizedDoubleBuffer似乎仅对WM_PAINT优化,而DateTimePicker的闪烁是由WM_ERASEBKGND引起的)

做个记录,以便后人查询。

 

更新:(2008/01/03)
    注意,这个Style仅仅被Window XP以上操作系统接受,如果在Window 2000下运行添加了这个Style的DateTimePicker将会产生异常。

更新:(2008/02/03)
    注意,这个Style会导致DateTimePicker的DropDownButton没有按下效果。因此,不建议在项目中使用这个方案。关于更详细的解决方案,稍后我重新写一篇Blog。

posted @ 2007-12-29 14:46 Colin Han 阅读(532) | 评论 (0)编辑

 

在.NET 2.0中,微软对.NET 1.0中提出的WinForm的AutoScale能力进行了调整和增强。但是,微软始终没有跳出快速开发的圈子,因此,AutoScale做的并不彻底。其中有些工作还必须我们自己完成。

1. 什么是AutoScale?

我们知道,在不同的操作系统版本或语言版本之间,系统的默认字体是不同的。Window还提供了用户设置DPI的能力。因此,很多时候,我们在特定版本和DPI下设计的窗体,在另外一个操作系统下就会有一些字或图片被裁掉。如下图:

.NET提供了一套关于这个问题的解决方案。就是WinForm上的一组关于AutoScale的方法或属性。包括:

ContianerControl上有:

AutoScaleFactor property

AutoScaleDimensions property

CurrentAutoScaleDimensions property

AutoScaleMode property

PerformAutoScale method

Control上有:

Scale method

ScaleChildren method

GetScaledBounds method

一般情况下,微软会自动帮助你完成所有关于AutoScale的功能。你并不需要写特别的代码使用这些功能。

2.  AutoScale的实现细节

在DesignTime,系统会根据AutoScaleMode的设置不同,将一个参考值赋值给Form的AutoScaleDimensions属性。

例如:如果你选择AutoScaleMode为Font。DesignTime会自动为Form生成一行如下的代码来保存你设计时所使用的默认字体的宽和高:

this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);&nbsp;

Note: 当前系统为英文。因此,当前字体高度为13,宽度为6 

在运行时,CurrentAutoScaleDimensions属性会提取当前系统的相关设置。生成另外一个计算值。AutoScaleFactor属性表现了两个值的比值,作为下一步缩放的缩放因子。
比如,在日文系统下运行时,CurrenAutoScaleDimensions为(6f, 12f)。AutoScaleFactor为(1f, 0.9xxxf).

System.Win.Forms.ContainerControl会在OnLayout(还包括一堆其它的事件中)中对调用自己的 PerformAutoScale方法,其中对自己和它子孙调用Scale方法,并将AutoScaleFactor传入。从而实现调整他们的位置和大小,以适应当前操作系统的设置。

3. 使用AutoScale时需要注意的问题?

上面的实现应该说比较巧妙,加上Visual Studio的设计时支持。应该说已经可以完美的解决所有通过DesignTime设计的窗体或自定义控件。

但是,微软没有为这套系统进行完整的支持。如果你通过代码在运行时修改控件的位置或大小时,可以说你没有任何一个理想的方案来确保你的修改能够适应各种不同的操作系统设置。因为......当ContainerControl触发了PerformAutoScale方法后,为了确保下一次触发 PerformAutoScale方法不会累加操作,而将AutoScaleDimensions修改为和 CurrentAutoScaleDimensions一致。也就是说,你再也无法拿到设计时所使用的AutoScaleDimensions值。因此,你也就无法使用这套机制来确保你的修改操作可以兼容各种操作系统的设置。

在我们的产品中就有很多问题是这一点引起的。毕竟,在大多数产品中,并不会仅仅通过DesignTime托托拽拽就可以完成需求。因此,我们需要:

3.1 尽量使用DesignTime设置Control的Size和Location
3.2 如果不能使用DesignTime,自己需要维护AutoScaleDimensions值

看起来,我们只能自己手动生成我们自己的AutoScaleDimensions值。VS会将那一行代码生成在 InitializeComponents方法内部,该函数推出的时候,PerformAutoScale已经被调用,因此标准的 AutoScaleDimensions属性已经不能使用了。这里需要Hard Code。 // TODO: 谁有更好的建议?

并且在下列情况中手动对Control的Location或Size进行计算。

  • 修改Control的位置或大小时,手动计算正确的值。
  • 添加新Control到Controls之前,手动计算正确的Size和Location. 

我们需要使用前面我们自己维护的AutoScaleDimensions和当前容器的AutoScaleDimensions运算生成 AutoScaleFactor,然后自己计算新的位置和大小。这里,需要注意,不要参考Control的当前Size或Location。因为他们可能已经被Scale过一次了。

Note: 千万不要试图通过调用Control.Scale方法来完成计算。因为,ContainerControl的Scale方法会对所有子Control进行 Scale。但是,往往ContainerControl已经在它的构造函数中对它的子进行了Scale操作。结果相当于它的子进行了两次Scale。结果是错误的。

posted @ 2007-10-20 13:46 Colin Han 阅读(2082) | 评论 (2)编辑

 

以前,我们的开发人员和测试人员有时会发现一些类似下图的异常。

这些异常的发生往往都是看起来很随机,很难重现的。调用堆栈往往是空的。并且,当程序脱离IDE运行时,都不会发生这些异常。因此,我们经常认为这些异常是IDE的Bug导致。很少在意。(至少我以前是这样)

今天详细的看了一下MSDN中关于MDA的介绍。发现这些问题往往都是很重要的和潜在的问题。比如:PInvokeStackImbalance这个MDA能够帮助我们发现PInvoke的声明有问题。StreamWriterBufferedDataLost这个MDA可以帮助我们发现我们忘记调用StreamWriter.Close()方法。

因为很多MDA异常的触发都是在GC回收时进行的,因此表现比较随机。较难重现。

如果你希望自己控制监视哪些MDA异常,可以使用IDE中的Debug->Exceptions->Managing Debugging Assistants来选择捕获哪些MDA异常。如下图:

posted @ 2007-08-15 18:56 Colin Han 阅读(1012) | 评论 (3)编辑
据说Asp.NET 2.0提供了用户管理的基本框架和实现。按照这个框架可以很容易的实现Web网站的用户管理功能。
呵呵,今天想学习一下。

遇到的第一个问题,就是如何建立Asp.NET用户管理数据库。好在微软提供了一个向导来帮助你完成这个工作。只需要在Visual Studio 2005 Command Line下输入“aspnet_regsql”即可以启动向导。上面的链接中有比较细致的介绍。

可惜,我并不想在我的机器上安装Sql Server .只想使用VS2005自带的Sql Express版。但是,上面的向导中并没有对Express版的支持。郁闷

呵呵,微软还是做事很细致的,他为我么提供了命令行的方式。虽然,实现确实很隐晦。不管怎样,下面的代码可以成功的将数据库建立起来。

建立数据库Type text here)...aspnet_regsql -C "Data Source=.\SQLEXPRESS;Integrated Security=True;User Instance=True" -d "数据库文件路径和全名.mdf" -A all

如果你还希望添加Session State的支持,只需要在后面加上“-ssadd”就可以了。
如果你希望从数据库里面清理掉用户管理的支持,只需要将上文中的"-A"改为"-R"即可。注意,这里区分大小写。
当然移除Session State的指令是"-ssremove"

关于更多的命令行参数,还是各位看官自己查MSDN或运行下面的命令行查看吧。
查看aspnet_regsql的命令行支持aspnet_regsql /?


posted @ 2007-07-29 14:20 Colin Han 阅读(943) | 评论 (2)编辑
呵呵,对Cnblogs关注的时间很长了,也搭建了自己的技术博客。但是,平心而论,对博客园的贡献还是很小了。

关于博客园的商业化,谈点自己的想法:
首先我想问的是:为什么博客园需要商业化?

对于这个问题,我觉得可能也只能有两种解释。
a. 博客园的生存受到了威胁,如果不进行商业化,可能就会死掉。
b. 有很多好的想法,好的服务,因为资金的原因无法实现。

如果不是这两个原因中的一个,我觉得这个问题就不需要讨论了。:-)

我想,对于这两个问题的解决方案是完全不同的。

a. 经济问题影响了博客园的生存。
我不知道Dudu老大是怎样维持博客园的正常运作的。仅仅靠首页上的广告吗?相信Dudu老大对博客园的贡献和他的辛苦是我们每个人都不能比拟的。相信相对于他的付出,他的收入是很微薄的。Dudu老大希望能够将他辛勤的结果转换为对自己相对好的的回报是很正常的想法。
如果博客园目前真的遇到了这个问题。我想,商业化中所最需要注意的问题是:“如何在商业化的过程中确保Dudu对博客园的掌握”。
因为,生存才是商业化的主要目的。我们不能也没有必要追求过高的回报率。只要能够维持正常的运作和生活就可以了。
而Dudu对博客园的完全控制,才能够保证将来进行第二轮商业化的过程时不会引入太多的复杂因素。
如果希望解决这个问题,我建议在博客园内部寻求资源。比如:提供一些收费的服务。或引入一些赞助机制等。因为我相信,博客园中的大多数人和Dudu的利益是一致的。而大多数企业和我们的利益并不总是一致。因此,我完全反对这个时候引入企业赞助。企业的赞助会影响博客园的中立性,会在将来影响博客园的发展或转型。
希望Dudu千万不要在商业化面前迷失了自己。

b. 没有足够的资源为大家提供更好的服务
最近两天对于博客园商业化的讨论非常多,但是,在其中我没有看到我们需要提供哪些新的服务为博客园的作者和读者带来更多的价值的内容。
如果真的有这样的服务,我想,通过在这些增值服务上进行收费可能是一个解决经济问题的方案。同样,如果我们能够找到很好的服务。寻找VC也就不会很困难了。

哈哈,说了这么多,把自己想说什么都给忘了。简单来说:
1. 不要为了生存而放弃博客园的精神。什么是博客园的精神呢?我想:“分享、简单、纯洁”应该是我心目中的博客园的精神。
2. 寻找杀手服务,找到它,博客园就可以发展壮大。否则,我觉得不商业化也罢。

呵呵,我是一个作技术的人。想法简单。某些说法可能也有些尖刻。只是希望博客园能够越来越好。能够成为每一个在这里安家的人的永远的家园。:-)

posted @ 2007-07-09 20:34 Colin Han 阅读(1737) | 评论 (9)编辑

昨日,与一同事一起在修一个多线程下使用我们的控件产品的Bug。现将相关的经验发布在这里。

1. 标准WinForm控件不支持多线程访问

这一点,其实是Windows的机制。.NET 中每一个Control其实都是一个Window,使用这些Window,原则上都应该在创建这个Window的线程中。否则,会产生异常。这一点,似乎Windows也没有强制约束。某些操作可能会扔异常,而有些情况下却不会。比如:访问这个Window的某些属性。

因此,.NET在Control上暴露了Invork方法,以实现将操作发送到Control所属的线程中执行。细节,可以参考我以前的一篇帖子

这一点,已经是标准做法。所以不能称之为Bug。

现在我们来看一下出现了什么Bug。用户的应用程序中,某些时候需要启动一个新的线程,在这个线程中构造并显示一个Form,其中包含我们的控件。当用户启动后,发现我们的产品不能够正确地显示。

什么原因呢?

2. 静态成员是元凶

根据经验,这种情况下的问题一般都出在静态成员上。我们在开发中,经常为了优化性能,而将一些对象缓存在静态成员中。如果我们将一个包含Window的对象缓存在静态对象中,对它的调用就可能会产生异常。

大家都知道,静态成员是属于整个AppDomain的,也就是说,所有的线程在共享同一个静态对象。当另外一个线程调用静态对象上的方法时,根据前面的规则(WinForm控件不支持多线程访问),异常产生了。

呵呵,这一点,是我在以前修Bug中的经验。但是,昨天似乎并不灵验。整个出现异常的部分没有发现缓存静态的Window对象。

经验告诉我,肯定是静态成员惹得祸。先看出问题的代码,发现这里缓存了一个静态的Bitmap。

难道是,这个Bitmap不允许跨线程访问?对这个Bitmap对象进行了锁(Lock)操作后,发现问题解决。于是得出了下面的经验。

3. 某些GDI对象也不允许跨线程访问

GDI对象(包括GDI+对象)都是有Handle的。可能在某些情况下,微软也不保证跨线程访问的可靠性。从昨天的调试结果来看,这些对象应该是不允许多个线程并发访问。这一点并没有太多的跟踪和调试,如果你有兴趣,可以尝试的再跟一下。

通过对这些对象加锁,避免并发访问,似乎问题已经解决。但是因为这一部分被使用的非常频繁(否则我们也不加Cache了),加锁后,发现对控件的性能产生很大的影响。看来仅仅加锁是不能解决所有问题的。

于是,昨天从Winking那里学了一着。

4. System.ThreadStaticAttribute

这个属性标示一个静态对象在每个线程中是独立的。因此,我们只要在这些缓存字段上加上这个属性。哈哈,问题解决。喔,看起来解决的太轻松了。先别急,现实往往比想象中残酷。

5. 静态对象的初始化的问题

我们一般会使用两种方式初始化静态对象。静态构造函数 和 第一次访问时。(我们经常会在静态对象的声明后面直接进行初始化,这种情况其实也是通过静态构造函数进行初始化的。只是编译器帮助我们将这些代码移动到了静态构造函数里面。因此,这里不单独讨论。)

如果我们将静态字段标记为线程唯一的,静态构造函数就不能够正确地初始化这个字段了。因为,静态构造函数只被调用一次。(它没有办法标记为线程唯一的:))

于是,这里就需要使用延迟构建模式。我们需要将这些静态成员声明为属性,在其Get函数中判断对象是否为空(或默认值,值类型)。从而确定是否需要构造缓存对象。 

6. 总结

呵呵,至此,所有的问题都解决了,Bug也已经修复。总体来说,静态对象始终是一个不安全因素。在目前我负责的项目中,我们是尽量避免使用静态成员。如果需要缓存对象,我们也会将这些缓存对象放在一个特定的池中。确保缓存对象是面向特定实例的而不是全局的。避免出现上面的问题。

相关文章:.NET下跨线程访问Control。

posted @ 2007-03-21 13:30 Colin Han 阅读(3797) | 评论 (10)编辑

一般情况下,安装VS 2005时,安装程序会自动配置本地IIS服务使用ASP.NET 2.0。我们可以直接在VS 2005下编写或调试WEB应用程序。

但是,如果我们先安装了VS2005,然后才安装的IIS。这时,IIS会设置为使用ASP.NET 1.0。我们在VS2005中建立WEB程序是会出现下面的提示:

The site 'http://localhost/xxxxxx' has not been configured for use with ASP.NET 2.0. Microsoft Visual Studio has been designed for use with ASP.NET 2.0; if not configured some features may make incorrect assumptions, and pages designed with the tool may not render correctly.

并且不能自动配置成功。

这时,只需要在Visual Studio 2005 Command Prompt中执行下面的命令

aspnet_regiis -i -enable

posted @ 2007-03-03 13:41 Colin Han 阅读(3854) | 评论 (3)编辑

 今天发现微软已经将.NET Framework 3.0添加到Windows Update中了。但是至少目前还没有放在自动更新中。

posted @ 2007-02-01 13:20 Colin Han 阅读(294) | 评论 (1)编辑
在反编译微软的代码后,发现下面的代码:
1 internal static int GetCombinedHashCodes(params int[] args)
2 {
3     int num1 -757577119;
4     for (int num2 = 0; num2 < args.Length; num2++)
5     {
6         num1 = (args[num2] ^ num1) * -1640531535;
7     }
8     return num1;
9 }
这个方法在System.Windows.Forms.WindowsFormsUtils中。

实在很想知道,其中的两个魔法数字有什么特别的,或者只是某人心情好?

posted @ 2006-11-16 19:34 Colin Han 阅读(326) | 评论 (0)编辑
收藏一下,分享一下。
不多说了,自己看吧。:-)

Jensen Harris: An Office User Interface Blog : The Office 2007 UI Bible

powered by performancing firefox

posted @ 2006-11-15 13:41 Colin Han 阅读(388) | 评论 (0)编辑
因为工作需要,写了个简单的测试程序测试了一下List<T>, LinkedList<T>, Dictionary<TKey, TValue>, SortedList<TKey, TValue>的性能。

测试结果中有两点出乎意料:
1. LinkedList的内存占用很大,比List大了将近60%。
    我没有细看为什么多出这么多内存占用。但是如果用我自己写的一个单链表,内存占用比List低。因为工作重点不在这里,我也不打算细究为什么了。但是感觉上,LinkedList的优势应该在小数据量,频繁添加删除的场景下。

2. SortedList的访问性能比Dictionary低。
    一般认为向SortedList中添加节点的性能会比较低,因为它需要维护一个有序表,存在性能开销(当数据有序时,添加节点的开销大约是Dictionary的170%)。但是,事实上,对SortedList中节点的读写性能也要低于Dictionary(近7倍的开销)。这一点我觉得比较难以理解。

附件中是这次测试使用的程序,有兴趣的你,也许可以下载后试验一下,看看为什么是这样?

附件:http://www.cnblogs.com/Files/Cajon/TestListPerformance.zip

powered by performancing firefox

posted @ 2006-08-27 15:55 Colin Han 阅读(6778) | 评论 (0)编辑