首页 新闻 论坛 群组 Blog 文档 下载 读书 Tag 网摘 搜索 .NET Java 游戏 视频 人才 外包 数据库 第二书店 程序员

Tag/ 


共3288个网摘 [ 1  2  3  4  5  6  7 ... 110 ]  上一页 | 下一页  |  

InfoQ: ASP.NET上的ReCAPTCHA类库

futurelight收录,使用标签:.NET,时间:2008-10-6 10:26:43 | 相关网摘我也收藏

【InfoQ中文站】reCAPTCHA ASP.NET类库提供了一个非常简单直观的方式,在您的ASP.NET站点上放置一个CAPTACHA组件,以此避免网站受到机器人的干扰。这个类库封装了reCAPTCHA API。您可以使用C#或Visual Basic.NET等任何一种.NET语言来操作这个类库。

一个CAPTCHA程序能够生成一些人类能通过,但是目前的计算机却无法通过的测试。例如,人类能够阅读如下图中扭曲的文字,但是目前的计算机程序却无法将其识别出来:

.
reCAPTCHA中的扭曲文字是书籍数字化进程的产物:

为了使计算机能够获取人类知识以及更好的传播信息,目前已有多个项目正在设法将计算机时代之前的出版物进行数字化。书页首先被扫描成照片,然后使用“Optical Character Recognition”(OCR)技术将其转化为文字。
将图片内容转化为文字非常有用,因为书籍扫描成图片之后将很难被保存在小型的设备中,难以下载,并且无法进行查询。不过问题在于OCR技术并不完美(下图为OCR出错示例)。reCAPTCHA将计算机无法阅读的文字通过CAPTCHA的方式在Web页面上展现出来,由人进行识别,并以此为书本数字化的进程做出贡献。具体地说,就是将OCR无法正确识别的单词以图片的方式显示并作为CAPTCHA来使用。这个做法是可行的,因为大部分的OCR程序在无法正确识别单词时将给出提示。


不过,既然计算机无法阅读此类CAPTCHA,系统又如何知道这个问题的正确答案呢?它的工作方式在于,每个OCR无法识别的新单词将会和另一个已经确定的单词一起提供给用户,而用户会被告知同时输入两个单词。如果答案已知的单词被正确输入,那么系统假设新的单词也是正确的。为了提高准确率,无论输入的结果是否正确,系统都会生成新的图片让其他一些用户再次进行辨认。

目前,我们正在帮助Internet Archive里的书籍以及旧版纽约时报进行数字化。
如果您要使用reCAPTCHA.NET:


微软新品Windows基础商务服务器意在中型商务市场

futurelight收录,使用标签:.NET,时间:2008-10-6 10:18:30 | 相关网摘我也收藏

【InfoQ中文站】微软推出了一款名为“Windows基础商务服务器(EBS)2008/Windows Essential Business Server 2008 (EBS)”的新型服务器,将管理、消息和安全等功能集成到一个一体化的多服务器方案中。这一新品主要针对IT维护人员较少(1到3人)的中型商务市场。

根据微软的说法:

Windows基础商务服务器(EBS)2008从设计和定价等方面都是面向中型商务市场需求,是一款企业级的服务器解决方案。EBS 2008为管理集成的IT基础设施,如最新版的管理、消息和安全服务器技术等,提供了一个统一的管理控制台。
EBS基于Windows Server 2008构建,包含以下产品:

Windows Server 2008标准版
Microsoft System Center Essentials 2007
Windows SharePoint Services 3.0
Microsoft Exchange Server 2007标准版
Microsoft Forefront Security for Exchange Server
Microsoft Forefront Threat Management Gateway中型商务版
Microsoft SQL Server 2008标准版
EBS有两个版本:标准版和高级版。两个版本都包含三个服务器:管理(Management)、安全(Security)和消息(Messaging)等。另外,高级版还包括一个数据库服务器,比如SQL 2008标准版。据TechNet报道,管理服务器包含下面一些组件:


连载最后一期:大学生求职七大昏招(二十)缺少职业素养(5) - Leo——感谢生活! - CSDNBlog

terry_zhoujie收录,使用标签:职场, leo, 程序员, 求职, 老板, 薪水, 加薪, 简历, .net, java, 连载, 大学生求职七大昏招,时间:2008-9-29 19:27:52 | 相关网摘我也收藏

如果没有太多的社会实践经验,那么应届生在求职中只有素质取胜这一条路可走。别以为这里提到的素质太软,摸不着边际。其实这种职业素质是可以培养的。下面一起分享吧……


扩展.net安全机制 - 激烈振动@CSDN - CSDNBlog

lyhu收录,使用标签:.net,时间:2008-9-26 21:48:55 | 相关网摘我也收藏

.net安全机制涉及很多方面,这里只讲基本的基于角色的安全机制。.net提供了PrincipalPermission 类,PrincipalPermissionAttribute类以及IPrincipal派生类支持基于角色的安全控制。内建的支持使用很方便,但灵活性却不高。举个例子吧:


文章:使用ClickOnce细分发布版本

futurelight收录,使用标签:.NET,时间:2008-9-26 21:23:58 | 相关网摘我也收藏

【InfoQ中文站】ClickOnce让WinForms应用程序的部署轻而易举。不过它只能提供版本的升级,却无法做到针对不同用户提供不同的版本下载。不过,David Cooksey为大家提供了一种思路,即通过在ASP.NET中编写一个HttpHandler来实现对ClickOnce部署的版本细分。

详细信息,请阅读全文:使用ClickOnce细分发布版本。


InfoQ: Windows HPC Server 2008已经发布

futurelight收录,使用标签:.NET,时间:2008-9-26 21:23:28 | 相关网摘我也收藏

【InfoQ中文站】微软刚刚将其Windows High-Performance Computing (HPC) Server 2008交付于生产厂商。这一服务器版是Windows Compute Cluster Server 2003的后继者,同时代表了微软在高性能计算领域的最新解决方案。

Windows HPC Server 2008的目标定位于需要大规模处理的业务,比如数据仓库或者事务处理,从桌面到拥有数千内核的集群,它都可以良好地伸缩。根据微软的说法,该系统的关键特性有:

提升系统管理的生产率与集群的可交互性
通过集成的Visual Studio 2008快速开发HPC应用
从工作站到集群的无缝伸缩
Windows HPC Server 2008是Windows Compute Cluster Server 2003的后继者,基于Windows Server 2008构建。其许可证只充许集群的HPC运行于HPC Server 2008上运行。所有的计算节点必须是基于64位x86的硬件,支持最高128G内存,并不支持IA-64。

Windows HPC Server 2008 可以有180天的评估试用期。根据发布通告,其收费标准为每一节点475美元。关于价格和许可证的更多信息可以在其如何购买页面找到。关于Windows HPC Server 2008的更多信息可于微软的HPC站点找到,该站点还包括了常见问题页面。同时关于超级计算机的更多信息请参阅Top 500 Supercomputers列表。


C# 中的委托和事件

blue_maple收录,使用标签:.NET,时间:2008-9-26 13:44:17 | 相关网摘我也收藏

引言

委托 和 事件在 .Net Framework中的应用非常广泛,然而,较好地理解委托和事件对很多接触C#时间不长的人来说并不容易。它们就像是一道槛儿,过了这个槛的人,觉得真是太容易了,而没有过去的人每次见到委托和事件就觉得心里别(biè)得慌,混身不自在。本文中,我将通过两个范例由浅入深地讲述什么是委托、为什么要使用委托、事件的由来、.Net Framework中的委托和事件、委托和事件对Observer设计模式的意义,对它们的中间代码也做了讨论。
将方法作为方法的参数

我们先不管这个标题如何的绕口,也不管委托究竟是个什么东西,来看下面这两个最简单的方法,它们不过是在屏幕上输出一句问候的话语:

public void GreetPeople(string name) {
// 做某些额外的事情,比如初始化之类,此处略
EnglishGreeting(name);
}
public void EnglishGreeting(string name) {
Console.WriteLine("Morning, " + name);
}

暂且不管这两个方法有没有什么实际意义。GreetPeople用于向某人问好,当我们传递代表某人姓名的name参数,比如说“Jimmy”,进去的时候,在这个方法中,将调用EnglishGreeting方法,再次传递name参数,EnglishGreeting则用于向屏幕输出 “Morning, Jimmy”。

现在假设这个程序需要进行全球化,哎呀,不好了,我是中国人,我不明白“Morning”是什么意思,怎么办呢?好吧,我们再加个中文版的问候方法:

public void ChineseGreeting(string name){
Console.WriteLine("早上好, " + name);
}

这时候,GreetPeople也需要改一改了,不然如何判断到底用哪个版本的Greeting问候方法合适呢?在进行这个之前,我们最好再定义一个枚举作为判断的依据:

public enum Language{
English, Chinese
}

public void GreetPeople(string name, Language lang){
//做某些额外的事情,比如初始化之类,此处略
swith(lang){
case Language.English:
EnglishGreeting(name);
break;
case Language.Chinese:
ChineseGreeting(name);
break;
}
}

OK,尽管这样解决了问题,但我不说大家也很容易想到,这个解决方案的可扩展性很差,如果日后我们需要再添加韩文版、日文版,就不得不反复修改枚举和GreetPeople()方法,以适应新的需求。

在考虑新的解决方案之前,我们先看看 GreetPeople的方法签名:

public void GreetPeople(string name, Language lang)

我们仅看 string name,在这里,string 是参数类型,name 是参数变量,当我们赋给name字符串“jimmy”时,它就代表“jimmy”这个值;当我们赋给它“张子阳”时,它又代表着“张子阳”这个值。然后,我们可以在方法体内对这个name进行其他操作。哎,这简直是废话么,刚学程序就知道了。

如果你再仔细想想,假如GreetPeople()方法可以接受一个参数变量,这个变量可以代表另一个方法,当我们给这个变量赋值 EnglishGreeting的时候,它代表着 EnglsihGreeting() 这个方法;当我们给它赋值ChineseGreeting 的时候,它又代表着ChineseGreeting()方法。我们将这个参数变量命名为 MakeGreeting,那么不是可以如同给name赋值时一样,在调用 GreetPeople()方法的时候,给这个MakeGreeting 参数也赋上值么(ChineseGreeting或者EnglsihGreeting等)?然后,我们在方法体内,也可以像使用别的参数一样使用 MakeGreeting。但是,由于MakeGreeting代表着一个方法,它的使用方式应该和它被赋的方法(比如ChineseGreeting) 是一样的,比如:

MakeGreeting(name);

好了,有了思路了,我们现在就来改改GreetPeople()方法,那么它应该是这个样子了:

public void GreetPeople(string name, *** MakeGreeting){
MakeGreeting(name);
}

注意到 *** ,这个位置通常放置的应该是参数的类型,但到目前为止,我们仅仅是想到应该有个可以代表方法的参数,并按这个思路去改写GreetPeople方法,现在就出现了一个大问题:这个代表着方法的MakeGreeting参数应该是什么类型的?

NOTE:这里已不再需要枚举了,因为在给MakeGreeting赋值的时候动态地决定使用哪个方法,是ChineseGreeting还是 EnglishGreeting,而在这个两个方法内部,已经对使用“morning”还是“早上好”作了区分。

聪明的你应该已经想到了,现在是委托该出场的时候了,但讲述委托之前,我们再看看MakeGreeting参数所能代表的 ChineseGreeting()和EnglishGreeting()方法的签名:

public void EnglishGreeting(string name)
public void ChineseGreeting(string name)

如同name可以接受String类型的“true”和“1”,但不能接受bool类型的true和int类型的1一样。MakeGreeting的 参数类型定义 应该能够确定 MakeGreeting可以代表的方法种类,再进一步讲,就是MakeGreeting可以代表的方法 的 参数类型和返回类型。

于是,委托出现了:它定义了MakeGreeting参数所能代表的方法的种类,也就是MakeGreeting参数的类型。

NOTE:如果上面这句话比较绕口,我把它翻译成这样:string 定义了name参数所能代表的值的种类,也就是name参数的类型。

本例中委托的定义:

public delegate void GreetingDelegate(string name);

可以与上面EnglishGreeting()方法的签名对比一下,除了加入了delegate关键字以外,其余的是不是完全一样?

现在,让我们再次改动GreetPeople()方法,如下所示:

public void GreetPeople(string name, GreetingDelegate MakeGreeting){
MakeGreeting(name);
}

如你所见,委托GreetingDelegate出现的位置与 string相同,string是一个类型,那么GreetingDelegate应该也是一个类型,或者叫类(Class)。但是委托的声明方式和类却完全不同,这是怎么一回事?实际上,委托在编译的时候确实会编译成类。因为Delegate是一个类,所以在任何可以声明类的地方都可以声明委托。更多的内容将在下面讲述,现在,请看看这个范例的完整代码:

using System;
using System.Collections.Generic;
using System.Text;

namespace Delegate {
//定义委托,它定义了可以代表的方法的类型
public delegate void GreetingDelegate(string name);
class Program {

private static void EnglishGreeting(string name) {
Console.WriteLine("Morning, " + name);
}

private static void ChineseGreeting(string name) {
Console.WriteLine("早上好, " + name);
}

//注意此方法,它接受一个GreetingDelegate类型的方法作为参数
private static void GreetPeople(string name, GreetingDelegate MakeGreeting) {
MakeGreeting(name);
}

static void Main(string[] args) {
GreetPeople("Jimmy Zhang", EnglishGreeting);
GreetPeople("张子阳", ChineseGreeting);
Console.ReadKey();
}
}
}

输出如下:
Morning, Jimmy Zhang
早上好, 张子阳

我们现在对委托做一个总结:

委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法,可以避免在程序中大量使用If-Else(Switch)语句,同时使得程序具有更好的可扩展性。
将方法绑定到委托

看到这里,是不是有那么点如梦初醒的感觉?于是,你是不是在想:在上面的例子中,我不一定要直接在GreetPeople()方法中给 name参数赋值,我可以像这样使用变量:

static void Main(string[] args) {
string name1, name2;
name1 = "Jimmy Zhang";
name2 = "张子阳";

GreetPeople(name1, EnglishGreeting);
GreetPeople(name2, ChineseGreeting);
Console.ReadKey();
}

而既然委托GreetingDelegate 和 类型 string 的地位一样,都是定义了一种参数类型,那么,我是不是也可以这么使用委托?

static void Main(string[] args) {
GreetingDelegate delegate1, delegate2;
delegate1 = EnglishGreeting;
delegate2 = ChineseGreeting;

GreetPeople("Jimmy Zhang", delegate1);
GreetPeople("张子阳", delegate2);
Console.ReadKey();
}

如你所料,这样是没有问题的,程序一如预料的那样输出。这里,我想说的是委托不同于string的一个特性:可以将多个方法赋给同一个委托,或者叫将多个方法绑定到同一个委托,当调用这个委托的时候,将依次调用其所绑定的方法。在这个例子中,语法如下:

static void Main(string[] args) {
GreetingDelegate delegate1;
delegate1 = EnglishGreeting; // 先给委托类型的变量赋值
delegate1 += ChineseGreeting; // 给此委托变量再绑定一个方法

// 将先后调用 EnglishGreeting 与 ChineseGreeting 方法
GreetPeople("Jimmy Zhang", delegate1);
Console.ReadKey();
}

输出为:
Morning, Jimmy Zhang
早上好, Jimmy Zhang

实际上,我们可以也可以绕过GreetPeople方法,通过委托来直接调用EnglishGreeting和ChineseGreeting:

static void Main(string[] args) {
GreetingDelegate delegate1;
delegate1 = EnglishGreeting; // 先给委托类型的变量赋值
delegate1 += ChineseGreeting; // 给此委托变量再绑定一个方法

// 将先后调用 EnglishGreeting 与 ChineseGreeting 方法
delegate1 ("Jimmy Zhang");
Console.ReadKey();
}



NOTE:这在本例中是没有问题的,但回头看下上面GreetPeople()的定义,在它之中可以做一些对于EnglshihGreeting和ChineseGreeting来说都需要进行的工作,为了简便我做了省略。

注意这里,第一次用的“=”,是赋值的语法;第二次,用的是“+=”,是绑定的语法。如果第一次就使用“+=”,将出现“使用了未赋值的局部变量”的编译错误。

我们也可以使用下面的代码来这样简化这一过程:

GreetingDelegate delegate1 = new GreetingDelegate(EnglishGreeting);
delegate1 += ChineseGreeting; // 给此委托变量再绑定一个方法

看到这里,应该注意到,这段代码第一条语句与实例化一个类是何其的相似,你不禁想到:上面第一次绑定委托时不可以使用“+=”的编译错误,或许可以用这样的方法来避免:

GreetingDelegate delegate1 = new GreetingDelegate();
delegate1 += EnglishGreeting; // 这次用的是 “+=”,绑定语法。
delegate1 += ChineseGreeting; // 给此委托变量再绑定一个方法

但实际上,这样会出现编译错误: “GreetingDelegate”方法没有采用“0”个参数的重载。尽管这样的结果让我们觉得有点沮丧,但是编译的提示:“没有0个参数的重载”再次让我们联想到了类的构造函数。我知道你一定按捺不住想探个究竟,但再此之前,我们需要先把基础知识和应用介绍完。

既然给委托可以绑定一个方法,那么也应该有办法取消对方法的绑定,很容易想到,这个语法是“-=”:

static void Main(string[] args) {
GreetingDelegate delegate1 = new GreetingDelegate(EnglishGreeting);
delegate1 += ChineseGreeting; // 给此委托变量再绑定一个方法

// 将先后调用 EnglishGreeting 与 ChineseGreeting 方法
GreetPeople("Jimmy Zhang", delegate1);
Console.WriteLine();

delegate1 -= EnglishGreeting; //取消对EnglishGreeting方法的绑定
// 将仅调用 ChineseGreeting
GreetPeople("张子阳", delegate1);
Console.ReadKey();
}
输出为:
Morning, Jimmy Zhang
早上好, Jimmy Zhang
早上好, 张子阳

让我们再次对委托作个总结:

使用委托可以将多个方法绑定到同一个委托变量,当调用此变量时(这里用“调用”这个词,是因为此变量代表一个方法),可以依次调用所有绑定的方法。
事件的由来

我们继续思考上面的程序:上面的三个方法都定义在Programe类中,这样做是为了理解的方便,实际应用中,通常都是 GreetPeople 在一个类中,ChineseGreeting和 EnglishGreeting 在另外的类中。现在你已经对委托有了初步了解,是时候对上面的例子做个改进了。假设我们将GreetingPeople()放在一个叫 GreetingManager的类中,那么新程序应该是这个样子的:

namespace Delegate {
//定义委托,它定义了可以代表的方法的类型
public delegate void GreetingDelegate(string name);

//新建的GreetingManager类
public class GreetingManager{
public void GreetPeople(string name, GreetingDelegate MakeGreeting) {
MakeGreeting(name);
}
}

class Program {
private static void EnglishGreeting(string name) {
Console.WriteLine("Morning, " + name);
}

private static void ChineseGreeting(string name) {
Console.WriteLine("早上好, " + name);
}

static void Main(string[] args) {
// ... ...
}
}
}

这个时候,如果要实现前面演示的输出效果,Main方法我想应该是这样的:

static void Main(string[] args) {
GreetingManager gm = new GreetingManager();
gm.GreetPeople("Jimmy Zhang", EnglishGreeting);
gm.GreetPeople("张子阳", ChineseGreeting);
}

我们运行这段代码,嗯,没有任何问题。程序一如预料地那样输出了:

Morning, Jimmy Zhang

早上好, 张子阳

现在,假设我们需要使用上一节学到的知识,将多个方法绑定到同一个委托变量,该如何做呢?让我们再次改写代码:

static void Main(string[] args) {
GreetingManager gm = new GreetingManager();
GreetingDelegate delegate1;
delegate1 = EnglishGreeting;
delegate1 += ChineseGreeting;

gm.GreetPeople("Jimmy Zhang", delegate1);
}

输出:
Morning, Jimmy Zhang
早上好, Jimmy Zhang

到了这里,我们不禁想到:面向对象设计,讲究的是对象的封装,既然可以声明委托类型的变量(在上例中是delegate1),我们何不将这个变量封装到 GreetManager类中?在这个类的客户端中使用不是更方便么?于是,我们改写GreetManager类,像这样:

public class GreetingManager{
//在GreetingManager类的内部声明delegate1变量
public GreetingDelegate delegate1;

public void GreetPeople(string name, GreetingDelegate MakeGreeting) {
MakeGreeting(name);
}
}

现在,我们可以这样使用这个委托变量:

static void Main(string[] args) {
GreetingManager gm = new GreetingManager();
gm.delegate1 = EnglishGreeting;
gm.delegate1 += ChineseGreeting;

gm.GreetPeople("Jimmy Zhang", gm.delegate1);
}

输出为:
Morning, Jimmy Zhang
早上好, Jimmy Zhang

尽管这样做没有任何问题,但我们发现这条语句很奇怪。在调用gm.GreetPeople方法的时候,再次传递了gm的delegate1字段:

gm.GreetPeople("Jimmy Zhang", gm.delegate1);

既然如此,我们何不修改 GreetingManager 类成这样:

public class GreetingManager{
//在GreetingManager类的内部声明delegate1变量
public GreetingDelegate delegate1;

public void GreetPeople(string name) {
if(delegate1!=null){ //如果有方法注册委托变量
delegate1(name); //通过委托调用方法
}
}
}

在客户端,调用看上去更简洁一些:

static void Main(string[] args) {
GreetingManager gm = new GreetingManager();
gm.delegate1 = EnglishGreeting;
gm.delegate1 += ChineseGreeting;

gm.GreetPeople("Jimmy Zhang"); //注意,这次不需要再传递 delegate1变量
}

输出为:
Morning, Jimmy Zhang
早上好, Jimmy Zhang

尽管这样达到了我们要的效果,但是还是存在着问题:

在这里,delegate1和我们平时用的string类型的变量没有什么分别,而我们知道,并不是所有的字段都应该声明成public,合适的做法是应该public的时候public,应该private的时候private。

我们先看看如果把 delegate1 声明为 private会怎样?结果就是:这简直就是在搞笑。因为声明委托的目的就是为了把它暴露在类的客户端进行方法的注册,你把它声明为private了,客户端对它根本就不可见,那它还有什么用?

再看看把delegate1 声明为 public 会怎样?结果就是:在客户端可以对它进行随意的赋值等操作,严重破坏对象的封装性。

最后,第一个方法注册用“=”,是赋值语法,因为要进行实例化,第二个方法注册则用的是“+=”。但是,不管是赋值还是注册,都是将方法绑定到委托上,除了调用时先后顺序不同,再没有任何的分别,这样不是让人觉得很别扭么?

现在我们想想,如果delegate1不是一个委托类型,而是一个string类型,你会怎么做?答案是使用属性对字段进行封装。

于是,Event出场了,它封装了委托类型的变量,使得:在类的内部,不管你声明它是public还是protected,它总是private的。在类的外部,注册“+=”和注销“-=”的访问限定符与你在声明事件时使用的访问符相同。

我们改写GreetingManager类,它变成了这个样子:

public class GreetingManager{
//这一次我们在这里声明一个事件
public event GreetingDelegate MakeGreet;

public void GreetPeople(string name) {
MakeGreet(name);
}
}

很容易注意到:MakeGreet 事件的声明与之前委托变量delegate1的声明唯一的区别是多了一个event关键字。看到这里,在结合上面的讲解,你应该明白到:事件其实没什么不好理解的,声明一个事件不过类似于声明一个进行了封装的委托类型的变量而已。

为了证明上面的推论,如果我们像下面这样改写Main方法:

static void Main(string[] args) {
GreetingManager gm = new GreetingManager();
gm.MakeGreet = EnglishGreeting; // 编译错误1
gm.MakeGreet += ChineseGreeting;

gm.GreetPeople("Jimmy Zhang");
}

会得到编译错误:事件“Delegate.GreetingManager.MakeGreet”只能出现在 += 或 -= 的左边(从类型“Delegate.GreetingManager”中使用时除外)。
事件和委托的编译代码

这时候,我们注释掉编译错误的行,然后重新进行编译,再借助Reflactor来对 event的声明语句做一探究,看看为什么会发生这样的错误:

public event GreetingDelegate MakeGreet;

可以看到,实际上尽管我们在GreetingManager里将 MakeGreet 声明为public,但是,实际上MakeGreet会被编译成私有字段,难怪会发生上面的编译错误了,因为它根本就不允许在GreetingManager类的外面以赋值的方式访问,从而验证了我们上面所做的推论。

我们再进一步看下MakeGreet所产生的代码:

private GreetingDelegate MakeGreet; //对事件的声明 实际是 声明一个私有的委托变量

[MethodImpl(MethodImplOptions.Synchronized)]
public void add_MakeGreet(GreetingDelegate value){
this.MakeGreet = (GreetingDelegate) Delegate.Combine(this.MakeGreet, value);
}

[MethodImpl(MethodImplOptions.Synchronized)]
public void remove_MakeGreet(GreetingDelegate value){
this.MakeGreet = (GreetingDelegate) Delegate.Remove(this.MakeGreet, value);
}

现在已经很明确了:MakeGreet事件确实是一个GreetingDelegate类型的委托,只不过不管是不是声明为public,它总是被声明为private。另外,它还有两个方法,分别是add_MakeGreet和remove_MakeGreet,这两个方法分别用于注册委托类型的方法和取消注册。实际上也就是: “+= ”对应 add_MakeGreet,“-=”对应remove_MakeGreet。而这两个方法的访问限制取决于声明事件时的访问限制符。

在add_MakeGreet()方法内部,实际上调用了System.Delegate的Combine()静态方法,这个方法用于将当前的变量添加到委托链表中。我们前面提到过两次,说委托实际上是一个类,在我们定义委托的时候:

public delegate void GreetingDelegate(string name);

当编译器遇到这段代码的时候,会生成下面这样一个完整的类:

public sealed class GreetingDelegate:System.MulticastDelegate{
public GreetingDelegate(object @object, IntPtr method);
public virtual IAsyncResult BeginInvoke(string name, AsyncCallback callback, object @object);
public virtual void EndInvoke(IAsyncResult result);
public virtual void Invoke(string name);
}

关于这个类的更深入内容,可以参阅《CLR Via C#》等相关书籍,这里就不再讨论了。
委托、事件与Observer设计模式
范例说明

上面的例子已不足以再进行下面的讲解了,我们来看一个新的范例,因为之前已经介绍了很多的内容,所以本节的进度会稍微快一些:

假设我们有个高档的热水器,我们给它通上电,当水温超过95度的时候:1、扬声器会开始发出语音,告诉你水的温度;2、液晶屏也会改变水温的显示,来提示水已经快烧开了。

现在我们需要写个程序来模拟这个烧水的过程,我们将定义一个类来代表热水器,我们管它叫:Heater,它有代表水温的字段,叫做 temperature;当然,还有必不可少的给水加热方法BoilWater(),一个发出语音警报的方法MakeAlert(),一个显示水温的方法,ShowMsg()。

namespace Delegate {
class Heater {
private int temperature; // 水温
// 烧水
public void BoilWater() {
for (int i = 0; i <= 100; i++) {
temperature = i;

if (temperature > 95) {
MakeAlert(temperature);
ShowMsg(temperature);
}
}
}

// 发出语音警报
private void MakeAlert(int param) {
Console.WriteLine("Alarm:嘀嘀嘀,水已经 {0} 度了:" , param);
}

// 显示水温
private void ShowMsg(int param) {
Console.WriteLine("Display:水快开了,当前温度:{0}度。" , param);
}
}

class Program {
static void Main() {
Heater ht = new Heater();
ht.BoilWater();
}
}
}
Observer设计模式简介

上面的例子显然能完成我们之前描述的工作,但是却并不够好。现在假设热水器由三部分组成:热水器、警报器、显示器,它们来自于不同厂商并进行了组装。那么,应该是热水器仅仅负责烧水,它不能发出警报也不能显示水温;在水烧开时由警报器发出警报、显示器显示提示和水温。

这时候,上面的例子就应该变成这个样子:

// 热水器
public class Heater {
private int temperature;

// 烧水
private void BoilWater() {
for (int i = 0; i <= 100; i++) {
temperature = i;
}
}
}

// 警报器
public class Alarm{
private void MakeAlert(int param) {
Console.WriteLine("Alarm:嘀嘀嘀,水已经 {0} 度了:" , param);
}
}

// 显示器
public class Display{
private void ShowMsg(int param) {
Console.WriteLine("Display:水已烧开,当前温度:{0}度。" , param);
}
}

这里就出现了一个问题:如何在水烧开的时候通知报警器和显示器?在继续进行之前,我们先了解一下Observer设计模式,Observer设计模式中主要包括如下两类对象:

1. Subject:监视对象,它往往包含着其他对象所感兴趣的内容。在本范例中,热水器就是一个监视对象,它包含的其他对象所感兴趣的内容,就是temprature字段,当这个字段的值快到100时,会不断把数据发给监视它的对象。
2. Observer:监视者,它监视Subject,当Subject中的某件事发生的时候,会告知Observer,而Observer则会采取相应的行动。在本范例中,Observer有警报器和显示器,它们采取的行动分别是发出警报和显示水温。

在本例中,事情发生的顺序应该是这样的:

1. 警报器和显示器告诉热水器,它对它的温度比较感兴趣(注册)。
2. 热水器知道后保留对警报器和显示器的引用。
3. 热水器进行烧水这一动作,当水温超过95度时,通过对警报器和显示器的引用,自动调用警报器的MakeAlert()方法、显示器的ShowMsg()方法。

类似这样的例子是很多的,GOF对它进行了抽象,称为Observer设计模式:Observer设计模式是为了定义对象间的一种一对多的依赖关系,以便于当一个对象的状态改变时,其他依赖于它的对象会被自动告知并更新。Observer模式是一种松耦合的设计模式。
实现范例的Observer设计模式

我们之前已经对委托和事件介绍很多了,现在写代码应该很容易了,现在在这里直接给出代码,并在注释中加以说明。

using System;
using System.Collections.Generic;
using System.Text;

namespace Delegate {
// 热水器
public class Heater {
private int temperature;
public delegate void BoilHandler(int param); //声明委托
public event BoilHandler BoilEvent; //声明事件

// 烧水
public void BoilWater() {
for (int i = 0; i <= 100; i++) {
temperature = i;

if (temperature > 95) {
if (BoilEvent != null) { //如果有对象注册
BoilEvent(temperature); //调用所有注册对象的方法
}
}
}
}
}

// 警报器
public class Alarm {
public void MakeAlert(int param) {
Console.WriteLine("Alarm:嘀嘀嘀,水已经 {0} 度了:", param);
}
}

// 显示器
public class Display {
public static void ShowMsg(int param) { //静态方法
Console.WriteLine("Display:水快烧开了,当前温度:{0}度。", param);
}
}

class Program {
static void Main() {
Heater heater = new Heater();
Alarm alarm = new Alarm();

heater.BoilEvent += alarm.MakeAlert; //注册方法
heater.BoilEvent += (new Alarm()).MakeAlert; //给匿名对象注册方法
heater.BoilEvent += Display.ShowMsg; //注册静态方法

heater.BoilWater(); //烧水,会自动调用注册过对象的方法
}
}
}
输出为:
Alarm:嘀嘀嘀,水已经 96 度了:
Alarm:嘀嘀嘀,水已经 96 度了:
Display:水快烧开了,当前温度:96度。
// 省略...
.Net Framework中的委托与事件

尽管上面的范例很好地完成了我们想要完成的工作,但是我们不仅疑惑:为什么.Net Framework 中的事件模型和上面的不同?为什么有很多的EventArgs参数?

在回答上面的问题之前,我们先搞懂 .Net Framework的编码规范:

* 委托类型的名称都应该以EventHandler结束。
* 委托的原型定义:有一个void返回值,并接受两个输入参数:一个Object 类型,一个 EventArgs类型(或继承自EventArgs)。
* 事件的命名为 委托去掉 EventHandler之后剩余的部分。
* 继承自EventArgs的类型应该以EventArgs结尾。

再做一下说明:

1. 委托声明原型中的Object类型的参数代表了Subject,也就是监视对象,在本例中是 Heater(热水器)。回调函数(比如Alarm的MakeAlert)可以通过它访问触发事件的对象(Heater)。
2. EventArgs 对象包含了Observer所感兴趣的数据,在本例中是temperature。

上面这些其实不仅仅是为了编码规范而已,这样也使得程序有更大的灵活性。比如说,如果我们不光想获得热水器的温度,还想在Observer端(警报器或者显示器)方法中获得它的生产日期、型号、价格,那么委托和方法的声明都会变得很麻烦,而如果我们将热水器的引用传给警报器的方法,就可以在方法中直接访问热水器了。

现在我们改写之前的范例,让它符合 .Net Framework 的规范:

using System;
using System.Collections.Generic;
using System.Text;

namespace Delegate {
// 热水器
public class Heater {
private int temperature;
public string type = "RealFire 001"; // 添加型号作为演示
public string area = "China Xian"; // 添加产地作为演示
//声明委托
public delegate void BoiledEventHandler(Object sender, BoiledEventArgs e);
public event BoiledEventHandler Boiled; //声明事件

// 定义BoiledEventArgs类,传递给Observer所感兴趣的信息
public class BoiledEventArgs : EventArgs {
public readonly int temperature;
public BoiledEventArgs(int temperature) {
this.temperature = temperature;
}
}

// 可以供继承自 Heater 的类重写,以便继承类拒绝其他对象对它的监视
protected virtual void OnBoiled(BoiledEventArgs e) {
if (Boiled != null) { // 如果有对象注册
Boiled(this, e); // 调用所有注册对象的方法
}
}

// 烧水。
public void BoilWater() {
for (int i = 0; i <= 100; i++) {
temperature = i;
if (temperature > 95) {
//建立BoiledEventArgs 对象。
BoiledEventArgs e = new BoiledEventArgs(temperature);
OnBoiled(e); // 调用 OnBolied方法
}
}
}
}

// 警报器
public class Alarm {
public void MakeAlert(Object sender, Heater.BoiledEventArgs e) {
Heater heater = (Heater)sender; //这里是不是很熟悉呢?
//访问 sender 中的公共字段
Console.WriteLine("Alarm:{0} - {1}: ", heater.area, heater.type);
Console.WriteLine("Alarm: 嘀嘀嘀,水已经 {0} 度了:", e.temperature);
Console.WriteLine();
}
}

// 显示器
public class Display {
public static void ShowMsg(Object sender, Heater.BoiledEventArgs e) { //静态方法
Heater heater = (Heater)sender;
Console.WriteLine("Display:{0} - {1}: ", heater.area, heater.type);
Console.WriteLine("Display:水快烧开了,当前温度:{0}度。", e.temperature);
Console.WriteLine();
}
}

class Program {
static void Main() {
Heater heater = new Heater();
Alarm alarm = new Alarm();

heater.Boiled += alarm.MakeAlert; //注册方法
heater.Boiled += (new Alarm()).MakeAlert; //给匿名对象注册方法
heater.Boiled += new Heater.BoiledEventHandler(alarm.MakeAlert); //也可以这么注册
heater.Boiled += Display.ShowMsg; //注册静态方法

heater.BoilWater(); //烧水,会自动调用注册过对象的方法
}
}
}

输出为:
Alarm:China Xian - RealFire 001:
Alarm: 嘀嘀嘀,水已经 96 度了:
Alarm:China Xian - RealFire 001:
Alarm: 嘀嘀嘀,水已经 96 度了:
Alarm:China Xian - RealFire 001:
Alarm: 嘀嘀嘀,水已经 96 度了:
Display:China Xian - RealFire 001:
Display:水快烧开了,当前温度:96度。
// 省略 ...


国际观点:抛弃Linux使用Vista的40条理由

villa123收录,使用标签:.NET,时间:2008-9-24 15:33:34 | 相关网摘我也收藏

【CSDN编译】事情颇有点喜剧性,最开始iTWire大学的David M Williams写了一篇“5 reasons to upgrade from Windows Vista to Linux”的文章,表达了他作为Linux的支持者的观点。当然,我并不同意他的看法,作为一名记者,我撰写了一篇名为“10 reasons to stick with Vista and forget Linux. ”的文章作为回击。这又引起了其他Linux狂热爱好者的不满,其中Sam Varghese增加了10条理由发表了一篇“20 reasons to shed the Microsoft yoke and use Linux”的文章去论证他的观点,并且对我说:“要么停止,要么继续加倍。”

现在,作为一个对Vista相当满意并且支持它的人,同时出于搞笑的目的,我也要推翻那些Linux狂热爱好者的言论。我必须这样做,所以让我来说一下选择Vista抛弃Linux的40条理由吧。

1. Vista比Linux要更流行,一般而言,各项程序在Vista系统上比在Linux系统上运行的更好。
2. Vista有更为广泛的软件支持,这包括商业软件、免费软件、开源软件等各项第三方软件的支持。
3. 它同时也有最广泛的硬件支持,可能唯一不逊色与它的只有Windows XP了。
4. Vista可用的安全软件是最先进的,同时其数量也众多。
5. 它所集成的IE和Office软件仍是目前互联网浏览和公司办公是使用的黄金般的标准。

6. 它对于互联网和局域网的兼容性是最好的。
7. Vista为客户提供了完善的备份软件和解决方案。
8. 其对游戏的支持不可谓不强悍。
9. 这也是一款极容易使用和操作的系统。
10. 他提供了下属安全软件以便于安全的进行网络冲浪。

11. 总的来说,Vista和Windows是大部分行业所使用的,熟练使用Vista对于工作和商务上是很有利的。
12. Vista有多种浏览器及大量的插件可供安装,这样网络浏览将更完美。
13. 如果需要的话,它可以连接上至少2.5G台电话以进行网络连接。
14. 它也有最好的声音识别软件。
15. Vista有很不错的电力管理机制。

16. Skype的最高级版本集成在其中。
17. 它对Windows Mobile有很好的兼容性。
18. Vista有着先进的多媒体中心。
19. 最好的Tablet PC可以在Vista上体验。
20. 其开始菜单栏也有着独到之处。

21. 虽然界面和外观的美观与否是由个人的主观喜好决定的,但无疑Vista有着相当不错的界面和外观。
22. 为Vista的操作系统写软件的程序员是最好的。
23. 在Vista平台上可有多种虚拟化软件供使用。
24. Vista上有Bill Gates 和 Jerry Seinfeld演绎的复杂商业TV。
25. 它能运行Microsoft的OneNote。

26. Vista能提供很好的远程登陆功能。
27. 你可以用一系列软件自由的打造系统,这些都是系统的组成部分而不是第三方附加项。
28. 它的任务栏可以让你爱不释手。
29. Vista确实是一个优秀的版本。
30. 安装Vista的价格是不固定的,你可以在较低的花费和奢侈的配置之间任意选择。

31. 对于在线驱动搜索,Vista可以做到又好又快捷。
32. 它的错误报告机制和Windows系统更新功能都是最好的版本。
33. Vista提供了SP1版本以解决一些简单的问题。
34. 它完全支持精密高级的键盘、鼠标以及各种游戏的驱动。
35. 学习配置Vista比Linux要快,而且配置起来也更容易。

36. 如果出了问题,它比Linux更易于修理。
37. Vista的系统恢复可以让你省心不少。
38. 它拥有更多的商务OS支持。
39. Vista不会使你成为一个激烈的左倾主义者和反资本的社会主义者。
40. Vista有Microsoft这个大靠山。

这就是40条可靠的原因使我更喜爱Vista。

PS:此文全部观点均是原作者观点。


Asp.net夜话之四:Visual Studio 2005中容易被忽略的技巧

villa123收录,使用标签:.NET,时间:2008-9-23 18:05:53 | 相关网摘我也收藏

Asp.net夜话之四:Visual Studio 2005中容易被忽略的技巧



在今天我主要要介绍的有如下知识点:
Visual Studio 2005网站开发环境
任务管理器
配置外部工具
代码段管理器
发布网站



之所以要单独用一篇文章来介绍Visual Studio 2005这个集成开发环境,是因为在做企业培训的时候,发现很多程序员仅仅用了一些基本功能,这个好像也符合软件界一个“20%和80%法则”,就是80%的用户只用到了软件的20%的功能。确实有时候利用基本功能就足以进行开发了,但是有些功能能够方便我们的开发,有些能提高我们的开发速度,所以我觉得这些计较值得跟大家交流一下。


C#3.0新体验(一)

villa123收录,使用标签:.NET,时间:2008-9-23 18:03:48 | 相关网摘我也收藏

C#3.0新体验(一)

maotin

20080923

前言概述:
微软的脚步一直都很快,经常发现很多技术还没学就已经过时了(可能是本人学习能力低下);作为研发个人认为应该站在技术的前沿,一定要跟上新技术的脚步(没办法,不学这些东西,过一段时间饭碗要保不住的);
从2002开始做开发,一直以来都在用vs.net(c#),可以算的上使用.net的一个老程序员了,可是回头看看,居然对.net很多都不了解,或者是一知半解;(汗如泉涌)作为一个用了5,6年.net开发的程序员,居然只知道页面放控件要整齐好看,UI数据传递给业务层处理,然后调用数据层访问(工作主要处理内容),很长一段时间不知道asp.net为何物(以前一直做winform),开发使用的最原始的.net自带IDE工具,没有开发任何辅助工具,对架构设计没什么概念,项目管理不知如何下手,测试全靠手工点界面,性能优化没有效果,数据事务没有保障,安装部署从来不知道怎么弄,代码重构没有干过,设计模式只知道工厂... ...
实在有太多东西不懂,(省略号包含的内容太多)这两年刚开始接触asp.net开发,一个人摸着石头过河,走了不少弯路,到现在还在摸索,感觉好多基础的东西都是新的;对自己能力极度怀疑的情况下,同时对微软(当然包括其他WEB技术供应商)这些牛人们产生极度的愤慨,没事搞出那么多技术,让我还怎么活(能力较差,性格懒散类型),学好一个技术(点)还有N+1个在后面排着;
这两年忙着装修,娶媳妇(全是偷懒的借口),原来的一点技术上积累的老底已经过时,很多都用不上了,直接导致一个严重的后果:近两年没涨过工资,还要当心失业的问题(一家老小啊,还有万恶的银行贷款压迫),在诸多压力下,决定彻底改造,重新做人,争取早日刑满释放,TNND,应该说金盆洗手(攒个百八十万的,当然要算美金才行,这社会RMB不经花),于是乎,决定从基础学起,开始这个C#3.0历程,希望整理的这些资料能给各位有一点点帮助!

一.C# 3.0语言主要增强点

• 隐含类型局部变量

• 扩展方法

• 对象与集合初始化器

• 匿名类型

• Lambda表达式

• 查询表达式( LINQ )

• 表达式树




二.隐含类型局部变量

先来看看例句:

var i = 5;

var h=23.56;

var s = “C Sharp";

var intArr = new[] {1,2,3,4} ;

var a = new[] { 1, 10, 100, 1000 };

"var"这个关键字是不是很眼熟,javascript中经常用到(互相学习现在比较常见了),当然C#中var和javascript的var差别还是比较大。

1.var只能作为局部变量使用;

就是说var只能定义在一个方法里面,或者foreach,for,using等语句里面:

public class VarTest
{
private void test()
{
var i = 0;
}
}

2.var可以申明任何类型变量,可以根据后面的初始化语句自动推断类型;

这个和object有点像,但var是强类型,根据初始化表达式来定义变量的类型;

var i=0; i 是int类型

var str = "test"; str是string类型

3.var定义时,必须使用表达式初始化;

也就是必须定义成 var i=0; 没有初始化编译会报错,而且初始化值不能为null,编译器无法根据null来推断出局部变量的类型;初始值除了int,string等数据类型外,还可以使用new 一个对象作为初始值(从网上大家发表的看法,var使用最多的就是配合一个匿名类型的对象来使用,以及在Linq中使用)




//下面是网上某个网友写得博客,拷贝修改了一下!

配合匿名类型使用:

var a = new{ Name = "maotin" ,Age = 99};
Console.WriteLine(a.Name);
Console.WriteLine(a.Age);
在linq中应用:

int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
var queryLowNums =
from num in numbers
where num < 5
select num;
foreach (var s in queryLowNums)
{
Console.Write(s.ToString() + " ");
}

4.var使用建议

一般var不要像“var i=9;”这样使用,程序可读性不高;

在匿名类型中使用比较方便;foreach中使用也不错;

var只是语言层面的东西,编译器会在编译的时候通过类型推断把它换成真正的类型


InfoQ: 全新编程Q&A网站上线

futurelight收录,使用标签:.NET,时间:2008-9-22 17:38:21 | 相关网摘我也收藏

【InfoQ中文站】Stack Overflow是一个专门面向编程Q&A的网站,尽管目前仍然是beta版,但已正式上线。这个网站为程序员提供了一个自由问答的空间,旨在成为能够查找到所有编程问题答案的源泉。

Stack Overflow是一个非常简洁的网站,它只有一个目标,那就是保存所有可能的编程问题和网友提供的解答。该项目的创建者这样描述Stack Overflow:

Stack Overflow是一个专门面向程序员的协作编辑的Q&A网站,不限平台,不限语言。

这个网站的创建者之一——Joel Spolsky是Fog Creek Software的CEO,同时也是FogBugz(一个bug跟踪软件)的创建者,他谈到了自己与Jeff Atwood( Coding Horror博客的作者)创建该网站的原因。

每当在网上查找某个编程问题的解答时,假若运气好,你有可能在搜索结果的第四页可以找到相关的答案。再加上如果你很有耐心,你可能会在长达7页的上百条回复中找到你想要的那条。然而,这上百条的回复中可能有25%都是一些垃圾广告,当然也不能说所有的回复都没用。

...我相信编程社区如果能把Q&A与投票、编辑方式结合起来的话,肯定可以取得更好的效果。

Joel这样描述Stack Overflow的工作方式:



共3288个网摘 [ 1  2  3  4  5  6  7 ... 110 ]  上一页 | 下一页

Tag/相关标签



    网站简介广告服务网站地图帮助联系方式诚聘英才English 问题报告
    北京创新乐知广告有限公司 版权所有 京 ICP 证 070598 号
    Copyright © 2000-2008, CSDN.NET, All Rights Reserved