C#中的Class和Struct

 什么是class? class(类)是面向对象编程的基本概念,是一种自定义数据结构类型,通常包含字段、属性、方法、属性、构造函数、索引器、操作符等。.NET中,所有的类都最终继承自System.Object类,因此是一种引用类型,也就是说,new一个类的实例时,对象保存了该实例实际数据的引用地址,而对象的值保存在托管堆(managed heap)中。 什么是struct? struct(结构)是一种值类型,用于将一组相关的信息变量组织为一个单一的变量实体 。所有的结构都继承自System.ValueType类,因此是一种值类型,也就是说,struct实例分配在线程的堆栈(stack)上,它本身存储了值,而不包含指向该值的指针。所以在使用struct时,我们可以将其当作int、char这样的基本类型类对待。 比较: 相同点:语法类似。 不同点: class是引用类型,继承自System.Object类;struct是值类型,继承自System.ValueType类,因此不具多态性。但是注意,System.ValueType是个引用类型。 从职能观点来看,class更多表现为行为;而struct常用于存储数据。 class支持继承,可以继承自类和接口;而struct没有继承性,struct不能从class继承,也不能作为class的基类,但struct支持接口继承 class可以声明无参构造函数,可以声明析构函数;而struct只能声明带参数构造函数,且不能声明析构函数。因此,struct没有自定义的默认无参构造函数,默认无参构造器只是简单地把所有值初始化为它们的0等价值 实例化时,class要使用new关键字;而struct可以不使用new关键字,如果不以new来实例化struct,则其所有的字段将处于未分配状态,直到所有字段完成初始化,否则引用未赋值的字段会导致编译错误。 class可以是抽象类(abstract),可以声明抽象函数;而struct不能为抽象,也不能声明抽象函数。 class可以声明protected成员、virtual成员、sealed成员和override成员;而struct不可以,struct可以重载System.Object的3个虚方法,Equals()、ToString()和GetHashTable()。 class的对象复制分为浅拷贝和深拷贝,必须经过特别的方法来完成复制;而struct创建的对象复制简单,可以直接以等号连接即可。 class实例由垃圾回收机制来保证内存的回收处理;而struct变量使用完后立即自动解除内存分配。 作为参数传递时,class变量是以按址方式传递;而struct变量是以按值方式传递的。 我们可以简单的理解,class是一个可以动的机器,有行为,有多态,有继承;而struct就是个零件箱,组合了不同结构的零件。其实,class和struct最本质的区别就在于class是引用类型,内存分配于托管堆;而struct是值类型,内存分配于线程的堆栈上。由此差异,导致了上述所有的不同点,虽然在某些方面struct有性能方面的优势,但是在面向对象编程里,基本是class横行的天下。 那么,既然class几乎可以完全替代struct来实现所有的功能,那么struct还有存在的必要吗?答案是,至少在以下情况下,鉴于性能上的考虑,我们应该考虑使用struct来代替class: 实现一个主要用于存储数据的结构时,可以考虑struct。 struct变量占有堆栈的空间,因此只适用于数据量相对小的场合。 结构数组具有更高的效率。 提供某些和非托管代码通信的兼容性。

2012-06-29 · 1 min · bystander

c#温故而知新: 线程篇

上次的C#温故而知新:Stream篇 已经完结了,这次,JimmyZheng 开始更新线程了,转发收藏,持续更新,当然你也可以直接去看JimmyZheng的文章,欢迎学习交流 c#温故而知新: 线程篇(一):Thread c#温故而知新: 线程篇(二):线程池和异步线程

2012-06-24 · 1 min · bystander

WPF实现不规则窗体

这几天在想C# winform程序界面实在太单一,而我C#实现不规则窗体中也说了,如果用背景这种东西来做的话,效果很差,抗锯齿能力基本为0,所以我当时在博客园提问,然后园友有了很给力的回答,比如WPF来做,或者第三方插件,或者深入底层改写ONPaint函数的,今天没事,恰好看到了一篇文章讲这个的,于是,就做一个简单的Demo出来,华丽的效果有木有,先看效果图 在win 7下使用win+Tab切换效果也很华丽。就不演示了。 做起来还算比较简单,首先使用Microsoft Expression Design 4 设计一个界面,破解版什么的太多了,,软件界面和ps挺像,不过功能弱很多,自己操作操作就好了,我说一个问题,就是我当时想画一个空心的圆,也就是一个圆环,ps里大家都知道,直接选区相减就可以了,但是这个死活没找到,基本上最后这个界面所有的地方被找了一遍,猜了猜,才发现了, 具体操作如下,首先汇出一个圆形,然后在圆里面再绘出一个圆形,这时候选中第二次的这个小圆,点击屏幕右侧的那个箭头会出现高级选项, 然后选择混合模式为橡皮擦,就会擦去这个小圆,于是就只剩下一个圆环了。 画好以后,选择文件->导出,按如下设置, 会得到一个xaml文件,一会用 然后新建wpf项目,然后在解决方案资源管理器视图右键点击项目 导入现有项,把上一步的xaml文件导入 然后需要在app.xaml文件中进行设置,具体在<Application.Resources>标签内添加如下代码,中间那个文件名看情况而定。 <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="bystander.xaml"/> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> 然后打开“MainWindow.xaml”文件的设计视图,点击窗体边缘以选中窗体,在属性面板中更改AllowsTransparency及WindowStyle属性。 AllowsTransparency 指示窗体是否支持透明。选中 WindowStyle指示窗体边框样式,设为 None 为无边框。 然后呢在 MainWindow.xaml文件中添加如下代码, Background="{StaticResource back}" MouseDown="Window_MouseDown"> 最终代码是: <Window x:Class="WpfDemo.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525" AllowsTransparency="True" WindowStyle="None" Background="{StaticResource back}" MouseDown="Window_MouseDown"> </Window> 其中background那个是固定的,而MouseDown是为了给窗体写可以拖动的函数,函数名为Window_MouseDown你也可以自己制定 然后对着那个函数名点右键,如下图 导航到事件处理程序,然后在打开的函数里写上 if(e.ChangedButton==MouseButton.Left) this.DragMove(); 拖动功能就实现了。 至于添加关闭按钮的,我就不写了,很简单,代码里都有。可以参考源文件。 工程源码下载:WPFDemo 参考: http://www.cnblogs.com/SkyD/archive/2008/07/13/1242044.html http://www.cnblogs.com/yinyao/archive/2011/05/23/2054056.html

2012-06-23 · 1 min · bystander

C#WinForm实现不规则窗体

这个纯属娱乐,因为其实用的不是太多,因为非主流,非标准的界面不符合用户的体验,不符合可用性功能的某一条HE规则。 为了完成这个效果,首先需要自己动手画个你需要的界面出来,界面边缘需要是一种可以很好区别的颜色,比如纯蓝色,因为实现不规则窗体是让C#使边缘颜色透明化来实现的,所以需要唯一识别。因为我用的图是一张灰色的图,我然后圈了一个蓝色的边缘。 刚开始的图; 然后新建windows应用程序。创建windows窗体并设置窗体基本属性。 (1)将 FormBorderStyle 属性设置为 None。 (2)将窗体的 BackgroundImage 属性设置为先前创建的位图文件。不必将文件添加到项目系统中;这将在指定该文件作为背景图像时自动完成。 (3)将 TransparencyKey 属性设置为位图文件的背景色,本例中为蓝色。(此属性告诉应用程序窗体中的哪些部分需要设置为透明。 ) 上面两个步骤已经完成了不规则窗体自身显示效果的制作。 有人说在24位色以下的环境中可以显示正常,但在24位色以上时黄色背景不能消失,所以上述不能胜任24位色以上环境。但我看到了一种解决方法,那就是先将背景图片添加到资源文件,然后在窗体构造时为窗体设置背景图片: private void Form1_Load(object sender, EventArgs e){ Bitmap bmp = Properties.Resources.form2; bmp.MakeTransparent(Color.Blue); // bmp.MakeTransparent(Color.FromArgb(2,2,2));如果rgb则是这样用 this.BackColor = Color.Blue; this.BackgroundImage = bmp; this.TransparencyKey = Color.Blue; } 实测是可以的。 然后就是为窗体添加移动、关闭、最大最小化的事件。代码直接给出 private bool isMouseDown = false; //记录鼠标是否被按下 private Point position; //记录鼠标位置 private void Form1_MouseDown(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left) { int x = -e.X; int y = -e.Y; position = new Point(x, y); isMouseDown = true; } } private void Form1_MouseMove(object sender, MouseEventArgs e) { if (isMouseDown) { Point newPosition = Control.MousePosition; newPosition.Offset(position); this.Location = newPosition; } } private void Form1_MouseUp(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left) { isMouseDown = false; } } 还有其他一些比如关闭按钮的添加,都很简单,直接添加一个button,事件里写,两个选一个。 this.Close();//关闭此窗体 Application.Exit();//退出应用程序 我最终的效果是个圆,可以看到,锯齿很明显,我想要效果好的话,那个位图得好好设计。这个只是演示。。所以。。还有一种方法是链接1中提供的,有兴趣的可以试试。 工程源码下载:IrregularForm.7z 参考: http://www.cnblogs.com/KissKnife/archive/2006/10/02/520116.html http://allancandy.cnblogs.com/archive/2005/09/01/227814.html

2012-06-21 · 1 min · bystander

GET和POST有什么区别?及为什么网上的多数答案都是错的。

今天突然看到很多好的技术文章,转载收藏备用分享。 如果有人问你,GET和POST,有什么区别?你会如何回答? 我的经历 前几天有人问我这个问题。我说GET是用于获取数据的,POST,一般用于将数据发给服务器之用。 这个答案好像并不是他想要的。于是他继续追问有没有别的区别?我说这就是个名字而已,如果服务器支持,他完全可以把GET改个名字叫GET2。他反问道,那就是单纯的名字上的区别喽?我想了想,我觉得如果说再具体的区别,只能去看RFC文档了,还要取决于服务器(指Apache,IIS****)的具体实现。但我不得不承认,我的确没有仔细看过HTTP的RFC文档。于是我说,我对HTTP协议不太熟悉。这个问题也就结束了。 最普遍的答案 回来之后寻思了很久,他到底是想问我什么?我一直就觉得GET和POST没有什么除了语义之外的区别,自打我开始学习Web编程开始就是这么理解的。 可能很多人都已经猜到了,他要的答案是: 1. GET使用URL或Cookie传参。而POST将数据放在BODY中。 2. GET的URL会有长度上的限制,则POST的数据则可以非常大。 3. POST比GET安全,因为数据在地址栏上不可见。 但是很不幸,**这些区别全是错误的,**更不幸的是,这个答案还是Google搜索的头版头条,然而我根本没想着这些是答案,因为在我看来他们都是错的。我来一一解释一下。 GET和POST与数据如何传递没有关系 GET和POST是由HTTP协议定义的。在HTTP协议中,Method和Data(URL, Body, Header)是正交的两个概念,也就是说,使用哪个Method与应用层的数据如何传输是没有相互关系的。 HTTP没有要求,如果Method是POST数据就要放在BODY中。也没有要求,如果Method是GET,数据(参数)就一定要放在URL中而不能放在BODY中。 那么,网上流传甚广的这个说法是从何而来的呢?我在HTML标准中,找到了相似的描述。这和网上流传的说法一致。但是这只是HTML标准对HTTP协议的用法的约定。怎么能当成GET和POST的区别呢? 而且,现代的Web Server都是支持GET中包含BODY这样的请求。虽然这种请求不可能从浏览器发出,但是现在的Web Server又不是只给浏览器用,已经完全地超出了HTML服务器的范畴了。 知道这个有什么用?我不想解释了,有时候就得自己痛一次才记得住。 HTTP协议对GET和POST都没有对长度的限制 HTTP协议明确地指出了,HTTP头和Body都没有长度的要求。而对于URL长度上的限制,有两方面的原因造成: 1. 浏览器。据说早期的浏览器会对URL长度做限制。据说IE对URL长度会限制在2048个字符内(流传很广,而且无数同事都表示认同)。但我自己试了一下,我构造了90K的URL通过IE9访问live.com,是正常的。网上的东西,哪怕是Wikipedia上的,也不能信。 2. 服务器。URL长了,对服务器处理也是一种负担。原本一个会话就没有多少数据,现在如果有人恶意地构造几个几M大小的URL,并不停地访问你的服务器。服务器的最大并发数显然会下降。另一种攻击方式是,把告诉服务器Content-Length是一个很大的数,然后只给服务器发一点儿数据,嘿嘿,服务器你就傻等着去吧。哪怕你有超时设置,这种故意的次次访问超时也能让服务器吃不了兜着走。有鉴于此,多数服务器出于安全啦、稳定啦方面的考虑,会给URL长度加限制。但是这个限制是针对所有HTTP请求的,与GET、POST没有关系。 安全不安全和GET、POST没有关系 我觉得这真是中国特色。我讲个小段子,大家应该可以体会出这个说法多么的可笑。 觉得POST数据比GET数据安全的人会说 _ “防君子不防小人;中国小白多,能防小白用户就行了。”_ _ “哼,”我不以为然,“那你怎么不说,_URL__参数都Encode__过了,或是Base64__一下,小白也看不懂啊。” 那人反驳道,_“_Encode__太简单了,聪明点儿的小白很容易就可以Decode__并修改掉。” 我笑道,_“五十步笑百步耳,再聪明点儿的小白还会截包并重发呢,_Opera__就有这功能。” 那人阴险地祭出神器——最终解释权,说,“这个不算小白。” 我日啊。 最后一点儿感想 我之前一直做Windows桌面应用,对Web开发无甚了解,直到一年多前转做服务器端开发,才开始接触到HTTP。(注意,我说的是HTTP,不是HTML。服务器开放接口是基于REST理念设计的,使用的协议是HTTP,但是传输的内容不是HTML。这不是Web Server,而是一个Web Service) 所以我对于GET和POST的理解,是纯粹地来源于HTTP协议。他们只有一点根本区别,简单点儿说,一个用于获取数据,一个用于修改数据。具体的请参考RFC文档。 如果一个人一开始就做Web开发,很可能把HTML对HTTP协议的使用方式,当成HTTP协议的唯一的合理使用方式。从而犯了以偏概全的错误。 可能有人会觉得我钻牛角尖。我只是不喜欢模棱两可,不喜欢边界不清、概念不明,不喜欢“拿来主义”,也不喜欢被其它喜欢钻牛角尖的人奚落得无地自容。 “知之为知之,不知为不知,是知也。” 原文链接:http://www.cnblogs.com/nankezhishi/archive/2012/06/09/2542968.html

2012-06-19 · 1 min · bystander

FreeAnony-代理采集设置工具

这个名字确实有点不太好。。因为刚开始我想到这个工具是在今天早上看到一个别人的代理工具的时候,突然想做的,没有好好规化,结果后来代码越写越多。。不过收获很大。 先看界面,因为是简单实现一下,所以就不要吐槽界面了。。 刚开始想的思路就是先去一个经常发布代理IP的网页去采集。然后解析成一条条的信息。然后显示出来。中途遇到几个问题,一个就是在做代理验证的时候,没有用多线程,导致直接界面无响应。另一个就是DataGridView控件要实现对一个数组的绑定,需要的一个实体对象。 public IPEntity[] GetIpInfo(string url) { //获得网页源码 string content = Get_Http(url); //定位代理ip位置 int start = content.IndexOf("</strong></u></a><BR>"); int end = content.LastIndexOf("<BR><SCRIPT type=text/javascript>"); //提取并去除一些冗余代码 string subContent = content.Substring(start, end - start).Substring(21); subContent = subContent.Replace("&nbsp; dn28.com", ""); //通过br标签分隔代理列表为数组 string[] sArray = Regex.Split(subContent, "<br>", RegexOptions.IgnoreCase); IPEntity[] list = new IPEntity[sArray.Length]; int j = 0; foreach (string i in sArray) { int addrpos = i.IndexOf(":"); string ipaddress = i.Substring(0, addrpos); int portpos = i.IndexOf("@"); string ipport = i.Substring(addrpos + 1, portpos - addrpos - 1); int typepos = i.IndexOf(";"); string iptype = i.Substring(portpos + 1, typepos - portpos - 1); string ipcountry = i.Substring(typepos + 1); list[j++] = new IPEntity(ipaddress, ipport, iptype, ipcountry); } return list; } 这部分就是先得到网页源码,然后通过IndexOf和LastIndexOf定位到ip组的位置。这是通过分析源码来确定参数的。最后通过 标签分割成字符数组。数组元素类似于112.25.12.37:80@HTTP;江苏省 移动,然后就是继续分割成一部分,构造了一个IPEntity的数组。在按钮中绑定到DataGridView中即可 IPEntity类的定义如下:这里面设置了一个status属性,用于后面代理验证的时候进行标记。 public class IPEntity { string _Address; string _Port; string _Type; string _Country; string _Status; public string Address { get { return _Address; } set { _Address = value; } } public string Port { get { return _Port; } set { _Port = value; } } public string Status { get { return _Status; } set { _Status = value; } } public string Type { get { return _Type; } set { _Type = value; } } public string Country { get { return _Country; } set { _Country = value; } } public IPEntity(string Address, string Port,string Type,string Country) { this._Address = Address; this._Port = Port; this._Type = Type; this._Country = Country; } } 然后是验证ip可用性的部分。这部分主要的代码是验证DataGridView中的ip地址可用性 ...

2012-06-17 · 2 min · bystander

gif反转工具

首先看下效果图: 然后是两张gif的对比 //原本图是正着走的 //处理后是倒着走的 gif是动态的嘛。然后我昨天和一个朋友聊天的时候发了一串相同的gif图,然后看着千篇一律的东西。我想能不能写个程序实现gif的初始状态不同呢。什么意思呢。我们知道,gif是由帧构成的,我想实现的功能是比如一个gif共有十帧,那么我写出来的程序能够生成10个gif文件,分别对应不同的初始状态来进行循环。后来一想,gif帧太多的话,比较慢,而且也不实用,于是决定简化一下,只做一个反转工具,比如一个gif是从左到右播放的,通过这个成功可以生成一个相同的gif图,不过是倒着播放的。 思路很简单,就是先把gif分解成很多帧,然后对帧进行合并,合并帧之前把帧的位置反转一下就可以了。因为我自己对图像处理的知识不懂,只想到了思路,所以这些功能都要找些资料,然后修改,测试。 分割帧的代码如下 //解码gif图片 public List<string> GetFrames(string pPath, string pSavedPath) { Image gif = Image.FromFile(pPath); FrameDimension fd = new FrameDimension(gif.FrameDimensionsList[0]); //获取帧数(gif图片可能包含多帧,其它格式图片一般仅一帧) int count = gif.GetFrameCount(fd); List<string> gifList=new List<string>(); //以Jpeg格式保存各帧 for (int i = 0; i < count; i++) { gif.SelectActiveFrame(fd, i); gif.Save(pSavedPath + "\\frame_" + i + ".png", ImageFormat.Png); gifList.Add(pSavedPath + "\\frame_" + i + ".png"); } return gifList; } 可以看到,返回了一个包含所有生成的帧地址的list列表。然后就是使用gifList作为参数来合并了。 //获取系统临时目录存放解码后的png图片 string temppath = System.Environment.GetEnvironmentVariable("TEMP"); List<string> gifList = GetFrames(tBoxFile.Text, temppath); gifList.Reverse(); String outputFilePath = "new.gif"; AnimatedGifEncoder ae = new AnimatedGifEncoder(); ae.Start(outputFilePath); ae.SetDelay(100); // 延迟间隔 ae.SetRepeat(0); //-1:不循环,0:总是循环 播放 for (int i = 0, count = gifList.Count; i < count; i++) { ae.AddFrame(Image.FromFile(gifList[i])); } ae.Finish(); MessageBox.Show("成功!新文件已保存在同目录"); 这里面使用了AnimatedGifEncoder这个类,这是Gif.Components.dll动态连接库里的类(此库开源,文末给出地址),是我在codeProject上找到的。首先我把gifList反转,然后合并保存到同目录。中间生成的帧为了方便我保存到了temp目录。 本来这个库里是分割gif的功能的。但是我实际测试后发现效果非常差,图片黑条泛滥,根本没法看。所以还是使用上面那段代码,相关代码我依然保存在工程里,有兴趣可以自己测试。 明天四级考试,求人品。。 项目源码:gif反转工具 参考: C#图片处理:获取GIF 动画图片中的各个帧 NGif, Animated GIF Encoder for .NET

2012-06-15 · 1 min · bystander

MySQL ERROR 1005: Can't create table (errno: 150)解决办法

最近在做数据库大作业,采用mysql建立数据库的时候出现了这个情况,查了一下,解决了。 出现问题的大致可能情况 1、外键的引用类型不一样,如主键是int外键是char 2、找不到主表中引用的列 3、主键和外键的字符编码不一致,也可能存储引擎不一样 对于第一个问题,检查一下自己的主外键记录数据类型是否一样,改了就行了,对于第二个问题,同样的道理,确定你主表中有对应的列。对于第三个问题 create table pw_test( uid int unsigned not null, primary key (uid), foreign key (uid) references pw_other(uid) on delete cascade on update cascade )ENGINE = MYISAM; 括号外面的语句设置了引擎。实战过程中通过。中间的外键设置了delete 和update约束。uid引用了pw_other表中的uid键 记下语法,出现问题的时候就可以用了。

2012-06-10 · 1 min · bystander

Turing机、人工智能以及我们的世界

 matrix67大牛太帅了。这篇文章给我很大的震撼,他传递的信息远不止计算机世界。强烈推荐,精彩的部分做了引用,事实上,全都很精彩啊。 昨天终于读完了《The Annotated Turing》一书,第一次完整地阅读了 Turing 最经典的那篇论文,理解了 Turing 机提出的动机和由此带来的一系列结论。不过,这本书的最大价值,则是让我开始重新认识和思考这个世界。在这里,我想把我以前积累的哲学观点和最近一些新的思考记下来,与大家一同分享。《The Annotated Turing》一书中的一些学术内容,留待以后几篇日志与大家分享。今年是 Alan Turing 诞辰 100 周年,图灵公司将推出这本书的中译本《图灵的秘密》,现在正在紧张的编辑排版中,不久之后就能和大家见面。 1928 年, David Hilbert 提出了一个著名的问题:是否存在一系列有限的步骤,它能判定任意一个给定的数学命题的真假?这个问题就叫做 Entscheidungsproblem ,德语“判定性问题”的意思。大家普遍认为,这样的一套步骤是不存在的,也就是说我们没有一种判断一个数学命题是否为真的通用方法。为了证明这一点,真正的难题是将问题形式化:什么叫做“一系列有限的步骤”?当然,现在大家知道,这里所说的“有限的步骤”指的就是由条件语句、循环语句等元素搭建而成的一个机械过程,也就是我们常说的“算法”。不过,在没有计算机的时代,人们只能模模糊糊地体会“一个机械过程”的意思。 1936 年,Alan Turing 在著名的论文《On computable numbers, with an application to the Entscheidungsproblem》中提出了一种假想的机器,第一次给了“机械过程”一个确凿的含义。 Turing 提出的机器非常简单。假设有一张无穷向右延伸的纸条,从左至右分成一个一个的小格子。每一个小格子里都可以填写一个字符(通常是单个数字或者字母)。纸条下方有一个用来标识“当前格子”的箭头,在机器运行过程中,箭头的位置会不断移动,颜色也会不断变化。不妨假设初始时所有格子都是空白,箭头的颜色是红色,并且指向左起第一个格子。为了让机器实现不同的功能,我们需要给它制定一大堆指令。每条指令都是由五个参数构成,格式非常单一,只能形如“如果当前箭头是红色,箭头所在格子写的是字符 A ,则把这个格子里的字符改为 B ,箭头变为绿色并且向右移动一格”,其中最后箭头的移动只能是“左移一格”、“右移一格”、“不动”中的一个。 精心设计不同的指令集合,我们就能得到功能不同的 Turing 机。你可以设计一个生成自然数序列的 Turing 机,或者是计算根号 2 的 Turing 机,甚至是打印圆周率的 Turing 机。 Turing 本人甚至在论文中实现了这么一种特殊的 Turing 机叫做通用 Turing 机,它可以模拟别的 Turing 机的运行。具体地说,如果把任意一个 Turing 机的指令集用 Turing 自己提出的一种规范方式编码并预存在纸条上,那么通用 Turing 机就能够根据纸条上已有的信息,在纸条的空白处模拟那台 Turing 机的运作,输出那台 Turing 机应该输出的东西。 但是, Turing 机并不是无所不能的。 Turing 证明了一个看似有些惊人的事实:不存在这样的一个 Turing 机,它能读取任意一个 Turing 机的指令集,并判断该 Turing 机是否将会在纸条上打印出至少一个 0 。注意,简单地用通用 Turing 机做模拟并不是一个可行的方案,因为模拟到现在还没有打出 0 ,不意味着今后也就永远不会打出 0 。这个定理有一个更深刻的含义,即没有一种通用的方法可以预测一台 Turing 机无穷远后的将来(后人把这个结论简化为了著名的停机问题)。正如《The Annotated Turing》封底上的一段文字所说:在没有计算机的时代, Turing 不但探索了计算机能做的事,还指出了计算机永远不能做到的事。 在论文的最后一章, Turing 给出了一种 Turing 机指令集和一阶逻辑表达式的转换规则,使得这个 Turing 机将会打出 0 来,当且仅当对应的一阶逻辑表达式为真。然而,我们没有一种判断 Turing 机是否会输出 0 的算法,因此我们也就没有一种判断数学命题是否为真的通用办法。于是, Entscheidungsproblem 有了一个完美的解答。 有趣的是,Turing 机本身的提出比 Entscheidungsproblem 的解决意义更大。计算机诞生以后,出现了五花八门的高级编程语言,一个比一个帅气,但它们的表达能力实际上都没有超过 Turing 机。事实上,再庞大的流程图,再复杂的数学关系,再怪异的语法规则,最终都可以用 Turing 机来描述。 Turing 机似乎是一个终极工具,它似乎能够表达一切形式的计算方法,可以描述一切事物背后的规律。在同一时代,美国数学家 Alonzo Church 创立了 λ 算子(λ-calculus),用数学的方法去阐释“机械过程”的含义。后来人们发现, Turing 机和 λ 算子是等价的,它们具有相同的表达能力,是描述“可计算性”的两种不同的模型。 Turing 机和 λ 算子真的能够描述所有直观意义上的“可计算数”、“可计算数列”、“可计算函数”吗?有没有什么东西超出了它们的表达能力?这个深刻的哲学问题就叫做 Church–Turing thesis 。当然,我们没法用形式化的方法对其进行论证,不过大家普遍认为, Turing 机和 λ 算子确实已经具有描述世间一切复杂关系的能力了。人们曾经提出过一些 hypercomputer ,即超出 Turing 机范围的假想机器,比如能在有限时间里运行无穷多步的机器,能真正处理实数的机器,等等。不过这在理论上都是不可能实现的。 ...

2012-06-02 · 2 min · bystander

比较HE和Think Aloud可用性测试

首先,HE和Think Aloud 都是两用可用性测试的方法,HE,也就是这个启发式评估可以在设计的早期阶段(比如草稿)就开始使用,并且不需要太多的其他步骤。而Think Aloud则更多建立在已经设计出来的原型系统上。需要更多的步骤。这两个各有利弊。互相协作。才能更好嘛,有些问题,HE可以发现,有些则只有Think Aloud可以发现。 1.Many Usability Aspects Identified in HE are Confirmed in Think-Aloud Usability Tests 许多可用性方面的问题可以在HE中识别。然后在Think Aloud测试中被确认。 2.When HE Predictions are not Confirmed by Think-Aloud Usability Tests 当HE预测了问题但是Think Aloud中,并没有发现。这种情况下。请相信Think Aloud测试。因为用户是王道。数据比预测更准确。 3.“False Alarms” vs. True Problems 假警告vs真问题,这个举个例子,在对话框中,有三个按钮。OK ,Apply和Cancel ,虽然HE规则预测了这个迷惑性。但是进行Think Aloud测试的时候,并没有这个问题,原因是用户就没想过这个事,他只按ok,但这并不能避免问题,或者说似乎这个问题并不是个问题,还有一种情况,比如HE规则中的文档帮助的问题,可能用户在测试的时候就没打开文档。这就需要HE来评估了。所以,这种情况下,还是应该好好分析一下HE给出的评估来改进系统。 4.Think-Aloud Usability Tests Can Show Things HEs Can’t Show Think Aloud测试可以展示HE没有发现的问题。 HE规则因为是建立在早期草稿原型上的。并不是真实情况,他只是在早期给出设计上的问题,他不能预测真实系统的问题,比如程序运行速度非常慢,以至于用户难以忍受。这就需要Think Aloud才能发现了。 基本上SSD4就讲了这么些东西了。四篇文章四点写到7点。。基本上算是写完了。工科男求安慰。。

2012-05-29 · 1 min · bystander