无题
随笔- 63  文章- 22  评论- 28 
博客园  首页  新随笔  联系  管理  订阅 订阅
2008年1月30日
软件开发的六大阶段 (指针经典原创)
 软件开发的六大阶段     CSDN Blog推出文章指数概念,文章指数是对Blog文章综合评分后推算出的,综合评分项分别是该文章的点击量,回复次数,被网摘收录数量,文章长度和文章类型;满分100,每月更新一次。
第一阶段:调研阶段

本阶段我们将组成企业项目调研组到企业进行现场调研,企业也部分需组织相应人员进行配合。整个调研工作将历时三星期到一个月左右时间。调研内容按以下方面进行。

1) 公司整体情况调研

目的:对企业的业务状况,组织结构,企业文化,发展战略进行仔细了解,从整体上对企业进行把握。 

2) OA系统调研 

目的:了解企业公文流转的方式,文档的管理,对使用OA系统的要求。在进行系统调研时,安派克公司将提供一个OA系统的原型供企业相关人员参考。

3) 人事工资系统调研

目的:了解企业现行的人事工资制度,将来可能的变化,对人事工资系统的要求。

4) 财务部门调研 

目的:掌握财务部门对信息管理的要求。了解财务部门与公司其余部门的关系。特别是和销售,物资,生产部门之间的关系及其信息流动。

5) 行政部门调研 

目的:了解行政部门的工作情况,在公司中的作用。了解行政部门和其它部门之间的关系,特别是和公司高级管理人员的关系。

6) 企业高级管理人员调研 

目的:了解企业高级管理人员对各部门信息管理的要求,以及对公司各类信息收集、汇总整理的要求,想法。

7) 企业Internet网页调研 目的:了解企业需要如何在Internet上展示自己的企业形象。向用户提供何种服务,对代理商,经销商如何提供技术支持等方面的内容。 

第二阶段:业务分析阶段

在完成第一阶段即调研阶段的工作后,我们将根据企业的目前状况,并且结合今后的发展情况,提出业务分析报告,供双方讨论确定。在此过程中如发现有争议,或不清楚的地方,还需要进行补充调研。

补充调研将采取电话,传真,E_MAIL等方式进行。待本报告的确认需经各具体业务部门确认。本分析阶段需要一到两个星期左右时间进行。 

第三阶段:需求分析阶段

作为Intranet系统开发初期进行的需求分析阶段的工作,由我们的系统分析员主持。经过了解企业的要求,认真细致地调研、分析,最终建立企业Intranet系统的逻辑模型并写出系统的需求说明书。 

需求分析在整个Intranet系统的开发过程中起着重要的作用,决定着系统开发的成败。在系统软件开发之前,首先应明确的是所要开发的软件应该具有哪些功能,应达到什么性能。明确了需求,就得到了系统设计开发的依据。

系统分析人员将到现场,全面了解用户的各项要求,澄清其中的模糊部分,对于哪些无法实现的要求,我们将与企业人员进行充分的协商,以得到一致的解决方案。

准确地表达被接受的用户要求也是需求分析的另一个重要方面,只有经过确切描述的要求才能成为设计的依据。我们最终将写出详尽的用户需求报告,提交给企业以确认。 

1、现场调查研究: 调查研究是需求分析中掌握资料的基础工作。 

2、确定需求: 确定需求就是要决定被开发的系统能够做什么,做到什么程度。这些需求包括: 

A、功能需求 列出系统在功能上应该做到什么。这是最主要的需求。 

B、性能需求 给出被开发系统工作时的技术性能指标。如响应时间、占用存储空间等。 

C、可靠性需求 提出系统不发生故障的概率。发生故障的解决方案等。 

D、安全和保密需求。 

E、资源使用需求 指系统运行时所需数据量大小,所需内存及硬盘容量、网络传输速率等。 

3、描述需求 已经确定下来的需求应该清晰、准确的描述。既编写系统需求说明书。 

4、需求分析复核 作为需求分析阶段工作的复核,在需求分析的最后一步,应对功能的正确性、完整性和清晰性以及其他需求予以评价。 

为保证系统开发的质量,复核应以企业与我们公司共同组成专门的审查小组进行审核。审核结束应有双方的结论意见及签字。后面的设计工作将完全以本需求报告为准。 

第四阶段:系统设计阶段

1、系统结构的总体设计 

决定系统的总体结构,包括整个系统分哪些部分,各部分之间有什么联系以及已确定的需求对这些组成部分如何分配等方面。 

2、数据结构的设计

决定数据库系统的模式、子模式以及数据完整性、安全性设计。 

3、完成用户使用手册的设计 

设计用户手册的结构、内容及编写风格等。 

4、制定初步的系统测试方案

对系统测试的策略、方法和步骤等提出明确的要求。 

5、编写系统概要设计报告 

6、概要设计评审 

在以上几项工作完成以后,我们对系统概要设计报告进行审核。审核通过后,进行系统的详细设计。 详细的系统设计进程请见"项目进度表" 

第五阶段:安装调试阶段

安装调试阶段实施的第一步是建立系统网络。网络的建立将由我们提供技术人员完成,他们将着重于检测该网络环境是否支持客户公司所选的系统,网络结构是否达到优化,是否可以使该系统稳定、高效地运行。 

安装调试阶段实施的第二步是系统的安装。系统安装的复杂程度因系统本身的复杂性而异。我们将根据具体情况对安装过程做适当的调整,例如:一些小型财务软件的安装只需要十几分钟,而大型系统,如SAP、JDEdwards、Baan等,其安装需要事先周密计划,各单位统一安装、协调进行,在这期间,我们将要求客户公司提供全面的配合。

整个安装过程包括在系统实施前必须规化网络结构,根据业务量确定各个子网规模;其次是设置网络操作环境及通信协议;然后再安装各类数据库服务器、应用服务器及备份服务器;最后是系统客户端软件的安装…在此全过程中均会涉及到硬件/网络、软件/数据库等各方面的匹配。此时客户公司与我们公司之间的协调和沟通就显得尤为重要了,所以我们建议双方在开始安装之前对系统的各个环节进行统筹安排,从而保证成功地完成这项复杂的系统安装。

我们的这套EAI系统将把系统的"客户化"放在首位,客户公司可以根据自身的特点来对系统中预留的各项参数进行设置。鉴于只有将企业的特点与软件的功能紧密结合才能使软件功能得到最大限度的发挥,所以参数的设置将在客户公司需求的基础上,结合我们的技术建议,经双方共同讨论后最后决定。 

第六阶段:技术培训阶段

为企业提供必要的系统维护培训(二至三名维护人员,为期一周),使其了解该系统的所有功能并熟练掌握整个系统的操作和日常维护,同时,我们公司负责为企业培训系统开发人员(二至三名,为期一周),使其掌握必要的开发技能。

当系统安装、调试完成,参数设置校验无误后,咨询人员将安排贵公司的培训,培训将根据用户在系统中的权限定义及责任范围分批分组进行。

应该强调的是,我们为贵公司员工的的培训不是仅针对系统的操作者,同时还注重培训用户自己的系统维护人员。由于该软件功能模块较多,同时为了满足贵公司让至少两名工作人员参与整个系统实施的全过程,包括用户培训,以便对整个系统的运作有全面的了解。在试运行/支持维护系统实施完毕后,需要有几个月的试运行,这是一个发现问题和解决问题的反复过程。我们也将在此过程中对系统的设置作进一步考核,同时对用户进行进一步的培训。 

总之,我们所提供的培训将帮助贵公司建立自己的内部协调及系统维护工作机制,以便最终提高系统的运行效率。


Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=601443
 面试十大难题的样板回答     CSDN Blog推出文章指数概念,文章指数是对Blog文章综合评分后推算出的,综合评分项分别是该文章的点击量,回复次数,被网摘收录数量,文章长度和文章类型;满分100,每月更新一次。

在面试前先了解、练习对几个很难的问题进行回答会帮助你对其他问题的回答做准备。有的问题问得比较多,有的较少但却是回答其它问题的基础。

1、为什么不谈谈你自己?

分析:这是个开放性问题。从哪里谈起都行,但是滔滔不绝地讲上一两个小时可不是雇主所希望的。这样的问题是测验你是否能选择重点并且把它清楚、流畅地表达出来。显然,提问者想让你把你的背景和想要得到的位置联系起来。

回答对策:有几个基本的方法。一个是直接简要回答所问的问题,另一个是在回答前要求把问题问得更明确。在上述两种情况下,你都要很快地把你的答案转到你的技能、经验和你为得到目前这份工作接受的培训上来。

回答样板:“我来自一个小家庭,有一个弟弟,父母都还在工作。中学毕业后,我攻读市场营销学士。日间在一家商业机构担任行销执行员,学了不少管理方面的知识。 例如,我全权负责的一个批发销售公司的业务,销售总额一年为200万美元。在那里我学习到怎么管理人事,在压力下解决问题。我希望能更好的运用我的技能。我相信我的经验和学历将让我迎向未来更大的挑战。”

评语:只简单的介绍了个人历史,很快的将重点话题转到与工作有关的技能和经验上来。你也可请面谈者把他确实想了解的东西集中到一点,如你可问:“你是不是想知道我受过的教育,或者与工作有关的技术和经验?”等,大多雇主都会乐意告诉你他们感兴趣的是什么?

2、我为什么要雇用你?

分析:这是个直接、正面的问题,尽管这个问题不会问得这样明确,但是会在其它问题之后被提出来,这个问题没有隐含的意思。

回答对策:直接的问题需要直接了当回答,为什么他们要雇用你呢?最巧妙的回答对他们而不是对你有利。这个问题会使你向他们提供证据以证实你可以帮助他们改进工作效率,降低成本、增加销售、解决问题(如准时上班,改进对顾客的服务、组织一个或多个管理工作等)。

回答样板:“我是个经验丰富的经理,在员工队伍建设方面,从组织项目的实施到鼓励员工合作,我得心应手。多年来,我已经掌握了一套雇人和留人的技巧。此外,我还擅长帮助公司顺利实现技术改造和员工培训。我经常对主要客户进行示范讲解,我们的销售额在过去两年平均增加了87%。”

评语:在回答中,以实例提供有力的证据,直接而自信地推销自己。

3、你有哪些主要的优点?

分析:像前面问题一样,这个问题问得相当直接,但是有一点隐含。

回答对策:你的回答应当首先强调你适应的或已具有的技能。雇用你的决定在很大程度上取决于这些技能,你可以在后面详细介绍你与工作有关的技能。回答时, 一定要简单扼要。

回答样板:“我具有朝著目标努力工作的能力。一旦我下定决心做某事,我就要把它做好,例如,我的志愿是成为一个出色的公关经理,我喜欢接触不同的人,服务人群,为了实现这个目标。我目前正在修读有关课程。”

评语:如“我的学习能力、适应能力很强。”“人际关系很好”等都是可提出的优点,但尽可能要提供与工作相关的证据,这会使你与众不同。

4、你有哪些主要的缺点?

分析:这是个棘手的问题。若照实的回答,你会毁了工作,雇主试图使你处于不利的境地,观察你在类似的工作困境中将作出什么反应。

回答对策:回答这样的问题应诚实。完满地回答应该是用简洁正面的介绍抵消反面的问题。

回答样板1:“工人们指责我对工作太投入。我经常提前一点上班安排好我的工作,晚上晚一点下班,使要干的事得以完成。”

回答样板2:“我需要学会更耐心一点。我的性子比较急,我总要我的工作赶在第一时间完成。我不能容忍工作怠慢。”

评语:回答的虽是自身的缺点,但却表现了正面的效果,对工作的积极抵消了反面。

5、你想得到的薪水是多少?

分析:如果你对薪酬的要求太低,那显然贬低自己的能力;如果你对薪酬的要求太高,那又会显得你分量过重,公司受用不起。一些雇主通常都事先对求聘的职位定下开支预算,因而他们第一次提出的价钱往往是他们所能给予的最高价钱。他们问你只不过想证实一下这笔钱是否足以引起你对该工作的兴趣。

回答对策:在商谈薪酬之前,你已经调查了解了自己所从事工作的合理的市场价值。在与对方商谈时,不妨尽可能插入“合理的和市场价值”语汇。记得,商谈时降低原来的开价轻而易举,但一旦开出低价后想再提上去就难乎其难。

回答样板1:如果你尚未彻底表现自我价值,面试者就提此问题考你,你不妨参考以下答案:

“钱不是我唯一关心的事。我想先谈谈我对贵公司所能做的贡献--如果您允许的话。”

“我对工资没有硬性要求。我相信贵公司在处理我的问题上会友善合理。我注重的是找对工作机会,所以只要条件公平,我则不会计较太多。”

回答样板2:如果你已经阐明该职位的重要性,可是对方仍旧告诉你给你的报酬已是最好的。您不妨指出它的工作性质实际上值得你获得更高的报酬;阐明你将如何通过努力缩减公司的开支;说明在工作中你得自我承担哪些费用等,以证明你对公司的价值,和表明你要求更高报酬是以你的工作表现为前提的。

但是如果对方不愿妥协,在你未得到肯定的工作答复之前,不要使雇主排除对你的考虑。你可以问:‘你们决定雇用我了吗?”如果答案是肯定的,报酬却使你不愿接受,你可以这样拒绝:

“谢谢你给我提供工作机会。这个职位我很想的到,但是,工资比我想要的低,这是我无法接受这份工作的原因之一。也许你会重新考虑,或者以后能有使我对你们更有价值的工作时再考虑我。”

评语:即使拒绝对方,也要为协商留有余地。如果雇主需要你,他会乐于满足你的要求。一旦你对他们提出的标准说“不”,交易就做不成了

6、你以前的经验和我们现在的工作有哪些联系?

分析:这个提问要求你在与其它求职者进行比较时,你要克服你背景中显示出来的任何弱点。

回答对策:首先要介绍你的优势。假如其它求职者明显地比你受的教育多,工作经验多或知识多,那么你就要介绍你的优势。

回答样板1:“如你所知,我刚刚结束电脑编程方面的加强培训。另外,我在企业方面有三年多的工作经验,其中包括在老板不在时管理小型企业。我在那学会了处理财务及基本的会计工作。我还盘算和管理过价值30万美元的产品。这些经历帮我认识企业使用电脑编程的作用。虽然我刚接触编程工作,我对电脑语言是熟悉的。我受的教育是全面的,我有300多个小时的电脑操作时间,这是我课程的一部分。因为我是新手,我决心比别人更努力地工作,以便及时完成任务。”

评语:这种回答强调了可转换性的技能(会计工作知识)和适应性技能(按时完成任务,更努力工作)。这对缺乏工作经验的程序员来说是必要的。在这种情况下,在学校学的知识也非常重要,也要像“正式”工作那样予以强调。

回答样板2:“在以前的工作中,我使用过很多与做好这项工作所需要的相同的技术。尽管是不同的企业,但管理企业都需要有我具有的组织和监督能力。在过去的七年里,我使我的部门成为我们公司最赢利的部门之一。在我工作期间,每年销售额平均上升30%,利润也提高30%。由于这是个老公司,这样的业绩是很不一般的,七年中我得到两次晋升,并很快地荣升到管理层。我想在你们这样小的、发展型公司接受挑战,我感到我的经验为我走向这一步做好了准备。”

评语:回答者明白以前的工作领域与现在考虑的不同,但是,他强调了成绩和以前的成功。为完成这项工作,各种管理技术都会用到。回答中还谈到继续接受小公司工作挑战的动力。

7、你对以后有什么打算?

分析:这个问题是在考察你的工作动机。它是在探究是否可以信赖你把工作长久地干下去,而且干得努力。

回答对策:你最好的对策就是诚实。这是一贯强调的。我并非是要你把负面的信息也摆出来,你应该准备坦率地、正面地回答雇主关心的问题。而哪些是雇主关心的问题取决于你介绍个人背景的具体情况。

例如:

你对工作满意吗? (如果不满意你会离开公司吗?)

你想成家吗? (如果成家,你会停职去照料小孩吗?)

你是否有过短期工作后离开的历史?(如果有,你会不会也放弃这份工作呢?)

你是否刚搬到此地,是临时的或暂住人口? (如果是,你也不会在此地久居,对吗?)

你是否有比本工作要求更好的条件?(如果是,是什么使你不去高就呢?)

你有什么优势和承诺在工作中发展吗?(如果不是,谁需要一个没有优势和动力的人呢?)

有什么原因使你感到不满吗? (如果有,雇主自然会设法搞清楚。)

回答样板1:对于一个刚刚参加工作的人,他可以这样回答:

“我认识到要在这一领域造就自己,我很愿意从此开始。我想过我要做什么,而且肯定我的技能正是做好这项工作所需要的。例如,我善于与人打交道。在我过去的一项工作中,我每周向1000多名不同的人提供服务。在我18个月的工作中,我曾为72000多名顾客提供服务,从未得到一次正式的投诉。事实上,他们常因我的周到服务表扬我。我认识到我喜欢与公众接触,想到我能得到这份工作感到非常愉快。我想在工作中更好地学习,并与之共同进步。由于我对公司的贡献和价值不断提高,我希望能考虑使我得到更有责任的职务。”

评语:雇主想了解你会长期工作下去并努力工作。这样的回答使对此表示关注的雇主感到安慰。(注意,这样的回答可以在快餐店工作获得的经验为背景。)

回答样板2:对没有工作经验和只有各种短期工作经验的人,他们可以这样回答:

“我做过几种工作(一种或失业),我认识到应该珍视体面的、稳定的工作。我的各种经验是一种财富,我学到很多东西,我可以把它们用于这项工作中去。我正在寻找一份可以安定下来,努力工作并持久下去的工作。”

评语:这是一种可以接受的回答,只是回答太短,也没有提供证据。介绍自己的实例最好放在最后一句话之前。有些职务,如销售方面的工作,要求你有勃勃雄心,或者说是咄咄勇气。其它工作有对工作领域或专门机构的要求。你不会总能预料到雇主想要什么。如果你能正确地做,你就会具有任何工作要求的条件,而这一切只需要你用嘴讲出来,就是这么简单。

8、你以前的雇主(教师、介绍人、管理员等)对你的评价如何?

分析:这个问题与雇主的第二种期望有关。雇主想知道你的适应性技能--你是否容易相处,你是否是个好工人等等。你以前的雇主可能会谈到你存在的问题,当然,也可能不谈。你知道,许多雇主会在雇用你之前查阅你的证明信,如果你在面谈时谈的与你以前的雇主说的不一样,你就要倒霉了。

回答对策:一定要与你以前的雇主讨论你的求职计划,也要征求你介绍人的意见。要明确地告诉他们你想找的工作种类以及你准备做好新工作的理由。假如以前的雇主会说一些不利于你的话,你要和他开诚布公地谈谈,看他会说写什么。

如果你是被解雇或被迫辞职的,你可以向未来的雇主进行辩解。有很多成功的人与前雇主发生过冲突,如果能把这些冲突尽可能地讲出来,许多面谈者是会理解的。对和你关系不好的旧雇主,明智的办法是请他写一份文字证明材料,在这种情况下,他们不会给你极为不利的信。大的公司一般不接受电话提供证明材料,这可以使你大大地松一口气,只要给公司打个电话就清楚了。

如果可能的话,使用那些说你好话的证明信。要是你的前任老板不愿这么做,找个愿意帮忙你的人便行了。如果你被解雇了,最好的对策是实话实说。但是对你的前任老板不要太苛刻,这样会让人觉得你是个好抱怨而无责任感的人。再者,你也不是一点错也没有。要先承认有这么回事,接着要趁机谈谈你从中得到的教训。

回答样板:“我的三个前雇主都会说我工作努力,可靠、忠实,我离开那里是因为个人冲突。为此我深深地感到烦恼,只有放弃那里的工作。你可以给他们打电话,他们对我的评价是肯定。我认为还是向你们谈谈为好,我仍然尊敬他。我在那得到了几次晋升的机会,但是,随着我权力的增加,冲突也越发地多起来。我们主要是不同类型的人。我不知道问题会有那么严重,因为我一心只想工作。这是我的错,我认识到我应该更加注意人际关系的处理。”

评语:回答中介绍了一些正面的技能,并用具体事例加以说明,因而是有力的。

9、你为什么要找这样的职位?为什么是在这里?

分析:雇主想了解是否你是那种无论什么公司有活就行的人。果真如此,他或她就不会对你感兴趣。雇主想找那种想解决工作中问题的人。他们有理由认为这样的人工作起来更努力,更有效率,而那些想去特别的公司工作的人也是如此。

回答对策:事先了解哪些工作适合你的技能和兴趣非常重要。要回答这个问题,就要谈到你选择工作目标的动机,那项工作要求的而你又具备的技能,各种专门培训,或与职务有关的教育证书。

这个问题实际上有两方面的含意。一是为什么选择这个职位,二是为什么选择这个公司。如果你有选择这个公司的理由,或选择这个公司是你最大愿望,你就要准备回答为什么。如果可能的话,在面谈前,你要事先尽可能地对它进行了解。与别人联系得到详细的情报,或到图书馆查阅,看公司的年度报告,或任何能使你了解情况的方法都是必要的。

回答样板:“我花费了很多时间考虑各种职业的可能性,我认为这方面的工作最适合我,原因是这项工作要求的许多技能都是我擅长的。举例来说,分析问题和解决问题是我的强项,在以前的工作中我能比别人更早发现和解决问题。有一次,我提出一项计划使得租借设备的退货率减少了15%,这听起来不算高,但是取得了年增长25000美元的好效益。而成本仅为100美元。目前你们公司似乎是能让我施展解决问题能力的地方。这个公司工作运行良好,发展迅速,善于接受新思想。你们的销售去年上涨了30%,而且你们准备引进几项大型新产品。如果我在这里努力工作,证实我自身的价值,我感到我有机会与公司共同发展。

评语:这种回答巧妙地运用了“提供证据”技巧,这样的话符合一个出色的经理或优秀的秘书的身份。

10、为什么不讲一讲你个人的情况?

分析:一个好的面谈者很少这样直接地提出这个问题,通过随意的、友好的谈话也可以得到想了解的情况。在大多数情况下,面谈者会竭力地打探证明你不稳定或不可靠的信息。

回答对策:还有其它一些可能使某个雇主关注的问题,以上问题只是对某些性格的人的推测。这都是些不相关的问题,但是,如果雇主想以此来了解你可否可靠,你就得全力以赴地去应付了。要记住即使是随意地闲谈也要避免提及隐晦的问题。在回答个人情况时,要态度友好而且自信。

回答样板:

有小孩子的家:“我有两个小孩,都在上学。他们和我的一个好朋友在一起,照料孩子不成问题。”

一人主家:“我没有结婚,但是我有两个孩子。对我来说有一份稳定的收入很重要,照料孩子不成为问题。”

年轻、单身:“我没有结婚,即使结婚,我也不会改变做专职工作的打算,我可以把全部精力用在工作上。”

新搬来的:“我决定在Depression Culch 长期居住下来,我租了一套公寓,搬家公司的六辆车正在卸家俱。”

抚养人:“我有个愉快的童年,我父母住的地方离我只需一小时飞机的路程,我一年去看他们几次。”

闲暇时间:“在我不去上班时,我主要呆在家里。我爱参加社区组织的活动,我每周都要在教堂参加活动。”

评语:上述回答都可以扩展开,可以做为你回答问题时的参考。这里要告诉面谈者的是你个人的情况不影响你的工作能力,而且,确实还能对你有帮助。如果你的个人生活会扰乱你的工作,想必雇主也会很快对你失去耐心的。这不是他们的问题,也不应该成为他们的问题。



Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=572207

 如何理解C/C++中的复杂类型声明(转)     CSDN Blog推出文章指数概念,文章指数是对Blog文章综合评分后推算出的,综合评分项分别是该文章的点击量,回复次数,被网摘收录数量,文章长度和文章类型;满分100,每月更新一次。

教你理解复杂的C/C++声明

                                                                          

                                                作者:Vikram A Punathambekar


介绍

曾经碰到过让你迷惑不解、类似于int * (* (*fp1) (int) ) [10];这样的变量声明吗?本文将由易到难,一步一步教会你如何理解这种复杂的C/C++声明:我们将从每天都能碰到的较简单的声明入手,然后逐步加入const修饰符和typedef,还有函数指针,最后介绍一个能够让你准确地理解任何C/C++声明的“右左法则”。需要强调一下的是,复杂的C/C++声明并不是好的编程风格;我这里仅仅是教你如何去理解这些声明。


基础

让我们从一个非常简单的例子开始,如下:

int n;

这个应该被理解为“declare n as an int”(n是一个int型的变量)。

接下去来看一下指针变量,如下:

int *p;

这个应该被理解为“declare p as an int *”(p是一个int *型的变量),或者说p是一个指向一个int型变量的指针。我想在这里展开讨论一下:我觉得在声明一个指针(或引用)类型的变量时,最好将*(或&)写在紧靠变量之前,而不是紧跟基本类型之后。这样可以避免一些理解上的误区,比如:

int*  p,q;

第一眼看去,好像是p和q都是int*类型的,但事实上,只有p是一个指针,而q是一个最简单的int型变量。

我们还是继续我们前面的话题,再来看一个指针的指针的例子:

char **argv;

理论上,对于指针的级数没有限制,你可以定义一个浮点类型变量的指针的指针的指针的指针...

再来看如下的声明:

int RollNum[30][4];
int (*p)[4]=RollNum;
int *q[5];

这里,p被声明为一个指向一个4元素(int类型)数组的指针,而q被声明为一个包含5个元素(int类型的指针)的数组。

另外,我们还可以在同一个声明中混合实用*和&,如下:

int **p1; // p1 is a pointer  to a pointer  to an int.
int *&p2; // p2 is a reference to a pointer  to an int.
int &*p3; // ERROR: Pointer  to a reference is illegal.
int &&p4; // ERROR: Reference to a reference is illegal.

注:p1是一个int类型的指针的指针;p2是一个int类型的指针的引用;p3是一个int类型引用的指针(不合法!);p4是一个int类型引用的引用(不合法!)。



const修饰符

当你想阻止一个变量被改变,可能会用到const关键字。在你给一个变量加上const修饰符的同时,通常需要对它进行初始化,因为以后的任何时候你将没有机会再去改变它。例如:

const int n=5;
int const m=10;

上述两个变量n和m其实是同一种类型的--都是const int(整形恒量)。因为C++标准规定,const关键字放在类型或变量名之前等价的。我个人更喜欢第一种声明方式,因为它更突出了const修饰符的作用。

当const与指针一起使用时,容易让人感到迷惑。例如,我们来看一下下面的p和q的声明:

const int *p;
int const *q;

他们当中哪一个代表const int类型的指针(const直接修饰int),哪一个代表int类型的const指针(const直接修饰指针)?实际上,p和q都被声明为const int类型的指针。而int类型的const指针应该这样声明:

int * const r= &n; // n has been declared as an int

这里,p和q都是指向const int类型的指针,也就是说,你在以后的程序里不能改变*p的值。而r是一个const指针,它在声明的时候被初始化指向变量n(即r=&n;)之后,r的值将不再允许被改变(但*r的值可以改变)。

组合上述两种const修饰的情况,我们来声明一个指向const int类型的const指针,如下:

const int * const p=&n // n has been declared as const int

下面给出的一些关于const的声明,将帮助你彻底理清const的用法。不过请注意,下面的一些声明是不能被编译通过的,因为他们需要在声明的同时进行初始化。为了简洁起见,我忽略了初始化部分;因为加入初始化代码的话,下面每个声明都将增加两行代码。

char ** p1;          //    pointer to    pointer to    char
const char **p2;        //    pointer to    pointer to const char
char * const * p3;       //    pointer to const pointer to    char
const char * const * p4;    //    pointer to const pointer to const char
char ** const p5;       // const pointer to    pointer to    char
const char ** const p6;    // const pointer to    pointer to const char
char * const * const p7;    // const pointer to const pointer to    char
const char * const * const p8; // const pointer to const pointer to const char

注:p1是指向char类型的指针的指针;p2是指向const char类型的指针的指针;p3是指向char类型的const指针;p4是指向const char类型的const指针;p5是指向char类型的指针的const指针;p6是指向const char类型的指针的const指针;p7是指向char类型const指针的const指针;p8是指向const char类型的const指针的const指针。



typedef的妙用

typedef给你一种方式来克服“*只适合于变量而不适合于类型”的弊端。你可以如下使用typedef:

typedef char * PCHAR;
PCHAR p,q;

这里的p和q都被声明为指针。(如果不使用typedef,q将被声明为一个char变量,这跟我们的第一眼感觉不太一致!)下面有一些使用typedef的声明,并且给出了解释:

typedef char * a; // a is a pointer to a char

typedef a b();   // b is a function that returns
          // a pointer to a char

typedef b *c;   // c is a pointer to a function
          // that returns a pointer to a char

typedef c d();   // d is a function returning
          // a pointer to a function
          // that returns a pointer to a char

typedef d *e;   // e is a pointer to a function
          // returning a pointer to a
          // function that returns a
          // pointer to a char

e var[10];     // var is an array of 10 pointers to
          // functions returning pointers to
          // functions returning pointers to chars.

typedef经常用在一个结构声明之前,如下。这样,当创建结构变量的时候,允许你不使用关键字struct(在C中,创建结构变量时要求使用struct关键字,如struct tagPOINT a;而在C++中,struct可以忽略,如tagPOINT b)。

typedef struct tagPOINT
{
  int x;
  int y;
}POINT;

POINT p; /* Valid C code */



函数指针

函数指针可能是最容易引起理解上的困惑的声明。函数指针在DOS时代写TSR程序时用得最多;在Win32和X-Windows时代,他们被用在需要回调函数的场合。当然,还有其它很多地方需要用到函数指针:虚函数表,STL中的一些模板,Win NT/2K/XP系统服务等。让我们来看一个函数指针的简单例子:

int (*p)(char);

这里p被声明为一个函数指针,这个函数带一个char类型的参数,并且有一个int类型的返回值。另外,带有两个float类型参数、返回值是char类型的指针的指针的函数指针可以声明如下:

char ** (*p)(float, float);

那么,带两个char类型的const指针参数、无返回值的函数指针又该如何声明呢?参考如下:

void * (*a[5])(char * const, char * const);



“右左法则”[重要!!!]

The right-left rule: Start reading the declaration from the innermost parentheses, go right, and then go left. When you encounter parentheses, the direction should be reversed. Once everything in the parentheses has been parsed, jump out of it. Continue till the whole declaration has been parsed.

这是一个简单的法则,但能让你准确理解所有的声明。这个法则运用如下:从最内部的括号开始阅读声明,向右看,然后向左看。当你碰到一个括号时就调转阅读的方向。括号内的所有内容都分析完毕就跳出括号的范围。这样继续,直到整个声明都被分析完毕。

对上述“右左法则”做一个小小的修正:当你第一次开始阅读声明的时候,你必须从变量名开始,而不是从最内部的括号。

下面结合例子来演示一下“右左法则”的使用。

int * (* (*fp1) (int) ) [10];

阅读步骤:
1. 从变量名开始 -------------------------------------------- fp1
2. 往右看,什么也没有,碰到了),因此往左看,碰到一个* ------ 一个指针
3. 跳出括号,碰到了(int) ----------------------------------- 一个带一个int参数的函数
4. 向左看,发现一个* --------------------------------------- (函数)返回一个指针
5. 跳出括号,向右看,碰到[10] ------------------------------ 一个10元素的数组
6. 向左看,发现一个* --------------------------------------- 指针
7. 向左看,发现int ----------------------------------------- int类型


总结:fp1被声明成为一个函数的指针,该函数返回指向指针数组的指针.


再来看一个例子:

int *( *( *arr[5])())();

阅读步骤:
1. 从变量名开始 -------------------------------------------- arr
2. 往右看,发现是一个数组 ---------------------------------- 一个5元素的数组
3. 向左看,发现一个* --------------------------------------- 指针
4. 跳出括号,向右看,发现() -------------------------------- 不带参数的函数
5. 向左看,碰到* ------------------------------------------- (函数)返回一个指针
6. 跳出括号,向右发现() ------------------------------------ 不带参数的函数
7. 向左,发现* --------------------------------------------- (函数)返回一个指针
8. 继续向左,发现int --------------------------------------- int类型

总结:??


还有更多的例子:

float ( * ( *b()) [] )();       // b is a function that returns a
                    // pointer to an array of pointers
                    // to functions returning floats.

void * ( *c) ( char, int (*)());    // c is a pointer to a function that takes
                    // two parameters:
                    //   a char and a pointer to a
                    //   function that takes no
                    //   parameters and returns
                    //   an int
                    // and returns a pointer to void.

void ** (*d) (int &,
char **(*)(char *, char **));    // d is a pointer to a function that takes
                    // two parameters:
                    //   a reference to an int and a pointer
                    //   to a function that takes two parameters:
                    //    a pointer to a char and a pointer
                    //    to a pointer to a char
                    //   and returns a pointer to a pointer
                    //   to a char
                    // and returns a pointer to a pointer to void

float ( * ( * e[10])
  (int &) ) [5];          // e is an array of 10 pointers to
                    // functions that take a single
                    // reference to an int as an argument
                    // and return pointers to
                    // an array of 5 floats. 



Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=569339

 浅谈指针的特点     CSDN Blog推出文章指数概念,文章指数是对Blog文章综合评分后推算出的,综合评分项分别是该文章的点击量,回复次数,被网摘收录数量,文章长度和文章类型;满分100,每月更新一次。

这是一篇我所见过的关于指针的最好的入门级文章,它可使初学者在很短的时间内掌握复杂的指针操作。虽然,现在的JAVA、C#等语言已经取消了指针,但作为一个C++程序员,指针的直接操作内存,在数据操作方面有着速度快,节约内存等优点,仍是很多C++程序员的最爱。指针就像是一把良剑,就看你怎么去应用它!


什么是指针?

  其实指针就像是其它变量一样,所不同的是一般的变量包含的是实际的真实的数据,而指针是一个指示器,它告诉程序在内存的哪块区域可以找到数据。这是一个非常重要的概念,有很多程序和算法都是围绕指针而设计的,如链表。


开始学习

  如何定义一个指针呢?就像你定义一个其它变量一样,只不过你要在指针名字前加上一个星号。我们来看一个例子:
  下面这个程序定义了两个指针,它们都是指向整型数据。


int* pNumberOne;
int* pNumberTwo;

  你注意到在两个变量名前的“p”前缀了吗?这是程序员通常在定义指针时的一个习惯,以提高便程序的阅读性,表示这是个指针。现在让我们来初始化这两个指针:
pNumberOne = &some_number;
pNumberTwo = &some_other_number;
  &号读作“什么的地址”,它表示返回的是变量在内存中的地址而不是变量本身的值。在这个例子中,pNumberOne 等于some_number的地址,所以现在pNumberOne指向some_number。 如果现在我们在程序中要用到some_number,我们就可以使用pNumberOne。


我们来学习一个例子:

  在这个例子中你将学到很多,如果你对指针的概念一点都不了解,我建议你多看几遍这个例子,指针是个很复杂的东西,但你会很快掌握它的。
  这个例子用以增强你对上面所介绍内容的了解。它是用C编写的(注:原英文版是用C写的代码,译者重新用C++改写写了所有代码,并在DEV C++ 和VC++中编译通过!)


#include <iostream.h>

void main()
{
// 声明变量:
int nNumber;
int *pPointer;


// 现在给它们赋值:
nNumber = 15;
pPointer = &nNumber;

//打印出变量nNumber的值:
cout<<"nNumber is equal to :"<< nNumber<<endl;

// 现在通过指针改变nNumber的值:
*pPointer = 25;

//证明nNumber已经被上面的程序改变
//重新打印出nNumber的值:
cout<<"nNumber is equal to :"<<nNumber<<endl;
}

  通读一下这个程序,编译并运行它,务必明白它是怎样工作的。如果你完成了,准备好,开始下一小节。


陷井!

  试一下,你能找出下面这段程序的错误吗?

#include <iostream.h>

int *pPointer;

void SomeFunction();
{
int nNumber;
nNumber = 25;


//让指针指向nNumber:
pPointer = &nNumber;
}

void main()
{
SomeFunction(); //为pPointer赋值

//为什么这里失败了?为什么没有得到25
cout<<"Value of *pPointer: "<<*pPointer<<endl;
}

  这段程序先调用了SomeFunction函数,创建了个叫nNumber的变量,接着让指针pPointer指向了它。可是问题出在哪儿呢?当函数结束后,nNumber被删掉了,因为这一个局部变量。局部变量在定义它的函数执行完后都会被系统自动删掉。也就是说当SomeFunction 函数返回主函数main()时,这个变量已经被删掉,但pPointer还指着变量曾经用过的但现在已不属于这个程序的区域。如果你还不明白,你可以再读读这个程序,注意它的局部变量和全局变量,这些概念都非常重要。
  但这个问题怎么解决呢?答案是动态分配技术。注意这在C和C++中是不同的。由于大多数程序员都是用C++,所以我用到的是C++中常用的称谓。

动态分配

  动态分配是指针的关键技术。它是用来在不必定义变量的情况下分配内存和让指针去指向它们。尽管这么说可能会让你迷惑,其实它真的很简单。下面的代码就是一个为一个整型数据分配内存的例子:
int *pNumber;
pNumber = new int;
  第一行声明一个指针pNumber。第二行为一个整型数据分配一个内存空间,并让pNumber指向这个新内存空间。下面是一个新例,这一次是用double双精型:
double *pDouble;
pDouble = new double;
  这种格式是一个规则,这样写你是不会错的。
  但动态分配又和前面的例子有什么不同呢?就是在函数返回或执行完毕时,你分配的这块内存区域是不会被删除的所以我们现在可以用动态分配重写上面的程序:
#include <iostream.h>

int *pPointer;

void SomeFunction()
{
// 让指针指向一个新的整型
pPointer = new int;
*pPointer = 25;
}

void main()
{
SomeFunction(); // 为pPointer赋值

cout<<"Value of *pPointer: "<<*pPointer<<endl;
}
  通读这个程序,编译并运行它,务必理解它是怎样工作的。当SomeFunction 调用时,它分配了一个内存,并让pPointer指向它。这一次,当函数返回时,新的内存区域被保留下来,所以pPointer始终指着有用的信息,这是因为了动态分配。但是你再仔细读读上面这个程序,虽然它得到了正确结果,可仍有一个严重的错误。

分配了内存,别忘了回收

  太复杂了,怎么会还有严重的错误!其实要改正并不难。问题是:你动态地分配了一个内存空间,可它绝不会被自动删除。也就是说,这块内存空间会一直存在,直到你告诉电脑你已经使用完了。可结果是,你并没有告诉电脑你已不再需要这块内存空间了,所以它会继续占据着内存空间造成浪费,甚至你的程序运行完毕,其它程序运行时它还存在。当这样的问题积累到一定程度,最终将导致系统崩溃。所以这是很重要的,在你用完它以后,请释放它的空间,如:
delete pPointer;
  这样就差不多了,你不得不小心。在这你终止了一个有效的指针(一个确实指向某个内存的指针)。
  下面的程序,它不会浪费任何的内存:

#include <iostream.h>

int *pPointer;

void SomeFunction()
{
// 让指针指向一个新的整型
pPointer = new int;
*pPointer = 25;
}

void main()
{
SomeFunction(); //为pPointer赋值
cout<<"Value of *pPointer: "<<*pPointer<<endl;

delete pPointer;
} 

  只有一行与前一个程序不同,但就是这最后一行十分地重要。如果你不删除它,你就会制造一起“内存漏洞”,而让内存逐渐地泄漏。
  (译者:假如在程序中调用了两次SomeFunction,你又该如何修改这个程序呢?请读者自己思考)

传递指针到函数

  传递指针到函数是非常有用的,也很容易掌握。如果我们写一个程序,让一个数加上5,看一看这个程序完整吗?:
#include <iostream.h>

void AddFive(int Number)
{
Number = Number + 5;
}

void main()
{
int nMyNumber = 18;

cout<<"My original number is "<<nMyNumber<<endl;
AddFive(nMyNumber);
cout<<"My new number is "<<nMyNumber<<endl;
//得到了结果23吗?问题出在哪儿?
}
  问题出在函数AddFive里用到的Number是变量nMyNumber的一个副本而传递给函数,而不是变量本身。因此, " Number = Number + 5" 这一行是把变量的副本加了5,而原始的变量在主函数main()里依然没变。试着运行这个程序,自己去体会一下。
  要解决这个问题,我们就要传递一个指针到函数,所以我们要修改一下函数让它能接受指针:把'void AddFive(int Number)' 改成 'void AddFive(int* Number)' 。下面就是改过的程序,注意函数调用时要用&号,以表示传递的是指针:
#include <iostream.h>
void AddFive(int* Number)
{
*Number = *Number + 5;
}

void main()
{
int nMyNumber = 18;

cout<<"My original number is "<<nMyNumber<<endl;
AddFive(&nMyNumber);
cout<<"My new number is "<<nMyNumber<<endl;
}


  试着自己去运行它,注意在函数AddFive的参数Number前加*号的重要性:它告诉编译器,我们是把指针所指的变量加5。而不并指针自己加5。

  最后,如果想让函数返回指针的话,你可以这么写:
int * MyFunction();
  在这句里,MyFunction返回一个指向整型的指针。


指向类的指针

  指针在类中的操作要格外小心,你可以用如下的办法定义一个类:
class MyClass
{
  public:
  int m_Number;
  char m_Character;
};
  接着你就可以定义一个MyClass 类的变量了:
MyClass thing;
  你应该已经知道怎样去定义一个指针了吧:
MyClass *thing;
  接着你可以分配个内存空间给它:
thing = new MyClass;
  注意,问题出现了。你打算怎样使用这个指针呢,通常你可能会写'thing.m_Number',但是thing是类吗,不,它是一个指向类的指针,它本身并不包含一个叫m_Number的变量。所以我们必须用另一种方法:就是把'.'(点号)换成 -> ,来看下面的例子:
class MyClass
{
public:
int m_Number;
char m_Character;
};

void main()
{
MyClass *pPointer;
pPointer = new MyClass;

pPointer->m_Number = 10;
pPointer->m_Character = 's';

delete pPointer;
}


指向数组的指针

  你也可以让指针指向一个数组,按下面的方法操作:
int *pArray;
pArray = new int[6];
  程序会创建一个指针pArray,让它指向一个有六个元素的数组。另外一种方法,不用动态分配:
int *pArray;
int MyArray[6];
pArray = &MyArray[0];
  注意,&MyArray[0] 也可以简写成 MyArray ,都表示是数组的第一个元素地址。但如果写成pArray = &MyArray可能就会出问题,结果是 pArray 指向的是指向数组的指针(在一维数组中尽管与&MyArray[0]相等),而不是你想要的,在多维数组中很容易出错。

在数组中使用指针

  一旦你定义了一个指向数组的指针,你该怎样使用它呢?让我们来看一个例子,一个指向整型数组的指针:

#include <iostream.h>

void main()
{
int Array[3];
Array[0] = 10;
Array[1] = 20;
Array[2] = 30;

int *pArray;
pArray = &Array[0];

cout<<"pArray points to the value %d\n"<<*pArray<<endl;
}

  如果让指针指向数组元素中的下一个,可以用pArray++.也可以用你应该能想到的pArray + 1,都会让指针指向数组的下一个元素。要注意的是你在移动指针时,程序并不检查你是否已经移动地超出了你定义的数组,也就是说你很可能通过上面的简单指针加操作而访问到数组以外的数据,而结果就是,可能会使系统崩溃,所以请格外小心。
  当然有了pArray + 1,也可以有pArray - 1,这种操作在循环中很常用,特别是while循环中。
  另一个需要注意的是,如果你定义了一个指向整型数的指针:int* pNumberSet ,你可以把它当作是数组,如:pNumberSet[0] 和 *pNumberSet是相等的,pNumberSet[1]与*(pNumberSet + 1)也是相等的。
  在这一节的最后提一个警告:如果你用 new 动态地分配了一个数组,
int *pArray;
pArray = new int[6];
  别忘了回收,
delete[] pArray;
  这一句是告诉编译器是删除整个数组而不一个单独的元素。千万记住了。

后话

  还有一点要小心,别删除一个根本就没分配内存的指针,典型的是如果没用new分配,就别用delete:

void main()
{
  int number;
  int *pNumber = number;

  delete pNumber; // 错误 - *pNumber 没有用new动态分配内存.
}


常见问题解答

Q:为什么我在编译程序时老是在 new 和 delete语句中出现'symbol undefined' 错误?
A:new 和 delete都是C++在C上的扩展,这个错误是说编译器认为你现在的程序是C而不C++,当然会出错了。看看你的文件名是不是.cpp结尾。

Q:new 和 malloc有什么不同?
A:new 是C++中的关健字,用来分配内存的一个标准函数。如果没有必要,请不要在C++中使用malloc。因为malloc是C中的语法,它不是为面向对象的C++而设计的。

Q:我可以同时使用free 和 delete吗?
A:你应该注意的是,它们各自所匹配的操作不同。free只用在用malloc分配的内存操作中,而delete只用在用new分配的内存操作中。

引用(写给某些有能力的读者)

  这一节的内容不是我的这篇文章的中心,只是供某些有能力的读者参考。
  有些读者经常问我关于引用和指针的问题,这里我简要地讨论一下。
  在前面指针的学习中,我们知道(&)是读作“什么的地址”,但在下面的程序中,它是读作“什么的引用”

int& Number = myOtherNumber;
Number = 25;
  引用有点像是一个指向myOtherNumber的指针,不同的是它是自动删除的。所以他比指针在某些场合更有用。与上面等价的代码是:
int* pNumber = &myOtherNumber;
*pNumber = 25;
  指针与引用另一个不同是你不能修改你已经定义好的引用,也就是说你不能改变它在声明时所指的内容。举个例子:
int myFirstNumber = 25;
int mySecondNumber = 20;
int &myReference = myFirstNumber;

myReference = mySecondNumber;//这一步能使myReference 改变吗?

cout<<myFristNumber<<endl;//结果是20还是25?

  当在类中操作时,引用的值必须在构造函数中设定,例:

CMyClass::CMyClass(int &variable) : m_MyReferenceInCMyClass(variable)
{
  // constructor code here
}


总结

  这篇文章开始可能会较难掌握,所以最好是多读几遍。有些读者暂时还不能理解,在这儿我再做一个简要的总结:
  指针是一个指向内存区域的变量,定义时在变量名前加上星号(*)(如:int *number)。
  你可以得到任何一个变量的地址,只在变量名前加上&(如:pNumber = &my_number)。
  你可以用'new' 关键字动态分配内存。指针的类型必须与它所指的变量类型一样(如:int *number 就不能指向 MyClass)。
  你可以传递一个指针到函数。必须用'delete'删除你动态分配的内存。
  你可以用&array[0]而让指针指向一个数组。
  你必须用delete[]而不是delete来删除动态分配的数组。



Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=568002


posted @ 2008-01-30 21:51 Borcala 阅读(207) 评论(0) 编辑
如何分层架构(杂记)
怎样分层:http://blog.csdn.net/llx529/archive/2005/08/15/455328.aspx


初学者,关于.net架构设计的问题?如何建立三层架构?from CSDN
最上层,数据访问data   access   layer,调用存储过程,运行sql语句.  
  中间曾,业务逻辑business   logic   layer,这一层封装业务逻辑,这一层调用数据访问层的方法.  
  用户界面User   interface.不用说了,这就是你的windows   form或者aspx页面.

简单点说,在你的项目里另外创建个两个文件夹,\dal和\bll  
  将数据访问类放到dal里,将所有的业务曾类创建到bll里.   
 

数据访问层,中间层都设计成类,编译生成dll  
  界面层,使用   DataLayer   obj   =   new   DataLayer();  
  obj.Method();  
  使用obj对象调用那中间层的方法。  
  中间层在调用数据层的方法。
接上面的,在dal里尽量数据库里一张表建一个类,bll里看你思路了
创建一个解决方案,添加需要的每层就可以了
就是表示层,业务逻辑层,数据访问层  
  参见petshop
csdn有好多文章是讲duwanmish的架构还有与petshop的比较你搜索下看看  
  层次是活的,但是我感觉就3层(数据层,业务逻辑层,表示层),其他的层都是为了程序的结构清晰或者代码的以维护移植等而进行扩充的。层其实就是个逻辑概念,通过做程序看别人的代码你还有你自己尝试用层来优化你的程序来体会层,光看是没有用的。

10 楼syeerzy(快乐永远*先天下之乐而乐*后天下之忧而忧*)回复于 2005-07-18 11:02:43 得分 30

新建一个空白解决方案。然后:  
   
  “添加”-“新建项目”-“其他项目”-“企业级模版项目”-“C#生成块”-“数据访问”(数据层,下简称D层)  
   
  “添加”-“新建项目”-“其他项目”-“企业级模版项目”-“C#生成块”-“业务规则”(业务层,下简称C层)  
   
  “添加”-“新建项目”-“其他项目”-“企业级模版项目”-“C#生成块”-“Web用户界面”(界面层,下简称U层)  
   
  右键点“解决方案”-“项目依赖项”,设置U依赖于C,C依赖于D。  
   
  对U添加引用C,对C添加引用D。  
   
   
  你想问的是这个????????   
   

Duwamiish7.0是五层  
  PetShop是三层

15 楼lyb_abiandbel(专注于OO分析与设计)回复于 2005-07-18 13:21:42 得分 10

这是我以前的学习petshop   3.0和duwamish   7.0的一点思考,  
   
  petshop是这样调用的:  
   
  (以product实体为例)实体product->BLL->DALFactory->IDAL->SQLServer   DAL  
   
   
  duwamish:  
   
  (以customer为例)customerdata数据->业务外观层GetCustomerByEmail()->数据访问层LoadCustomerByEmail()->Customer业务实体(这些业务实体全部是有DataSet承载)  
  ->调用存储过程->connetstring  
   
  提醒一下:调用接口函数实际上调用的是定义该接口函数的类的函数(记住这点才能清楚找到调用的过程)  
   
  以上是个人的理解,不知道能不能   帮你启发一下!

把每一层制作一个项目   然后引用他们的DLL文件到需要的项目里面   每层   也就是每个项目只作自己的事情   争取要作到出现错误或者升级维护只修改其中的一层   比如数据层   如果从SQL到ACCESS   你能保证只在数据库层修改。。。。。

听了lyb_abiandbel(渴望成为高手)   有所启发  
    TrojanSckiss所说的每一个层里都有.dll吗?我的目录里没有呀,是不是编译才能得到呢?
需要把你那层编译好以后在bin目录里面,在当前层添加引用,就可以使用以前的dll了。

如果你想学习,3层架构你就去看看java   的   MVC   框架比较好。  
   
  这个是java里面比较简单的一个了,你一定要记住页面流幺,呵呵。   .net的框架不够清晰。

不是.NET框架不清晰,而是太灵活了,所以出现了很多种框架,其实你自己结合实际选一种就可以了.  
  我一般也分三层,数据层(存储过程),业务逻辑层(一般用面向对象编写类),展现层(ASP.NET+WINDOW   FORM).  
  分析设计过程,先设计类,看看类里面要怎样访问数据库,再设计存储过程给类调用,最后用ASP.NET或WINDOW   FORM调用类中的方法实现系统   
 
++++++++++++++++++++
我对.NET不胜了解,不过,应该来说,.NET是一个平台,是一种面向INTERNET的分布式开发平台。而DNA还是建立在INTRANET范围以内的一种分布式架构。主要问题是以后的开发都向.NET转移,都是使用CLI库,不知道基于COM/DCOM/COM+的DNA架构位置在那里。还是请人进来继续讨论吧。
我的系分老师(在上海为软亚洲技术支持中心受训过)说,.NET是穿了一件漂亮外衣的DNA小姐。。。如果你扒光他的衣服,看到的就是DNA。

  不过,事实上两个构架的基础并不一样啊。.NET是基于CRL以及CRS等规范以及类库,而DNA架构是基于COM/DCOM/COM+,实在不知道有没有必要深入学习COM+知识了。彷徨中。。。
DNA是架构,软件模块的组织方式,系统模型.  
  而COM/COM+/.NET是具体的应用技术,解决手段.   
 
NET框架与COM                                     //ZT:中国   微软    
         
  背景和历史  
   
  可复用软件不是一个新概念。八年来,人们一直在使用各种形式的组件对象模型(COM)。事实证明,它是最为成功的可复用软件模型。COM引进了“组件”的概念——它是可复用的代码块,可以将多个独立函数的功能进行组合,从而扩充成诸如Microsoft   Word这样的应用程序。  
   
  大多数开发人员使用OLE时深刻体验了COM功能。OLE是基于COM形成的一组功能,使得用户能将一种文档嵌入到另一种文档中。这个功能本身似乎不太引人入胜,但它的作用却不同凡响:当用户将一个Excel文档粘贴到Word文档中后,单击嵌入的Excel文档时,OLE将会把Word的工具栏和菜单转换成Excel的工具栏和菜单。  
   
  从开发人员的角度看,COM通过引进几个明确定义的接口(诸如iUnknown)便可提供代码复用功能,开发期工具可通过这些接口来查询一个组件的功能,并能把这些功能添加到工具中。这就像Visual   Basic&reg;开发系统工具箱中的控件能够被拖到某个窗体中一样。实际上,每个控件都代表上百行甚至上千行的代码,可以容易地封装在“黑匣子”中,开发人员只需直接调用其功能即可。  
   
  开发人员在使用COM时感到不便的一个问题是,他们必须编写附加代码来将业务逻辑程序转换成可复用的组件,同时还必须实现许多接口才能进行这种转换。最重要的是,COM要求开发人员必须手动处理复杂问题,比如:清空不再使用的组件曾占用的内存、计算组件的使用次数、建立或撤消线程和进程以及处理版本控制问题等。  
   
  有人可能认为,让开发人员亲自执行这类工作的主意非常好,但这也有几个弊端。首先,要开发人员一一执行上述所有工作非常困难,往往容易出错:导致应用程序错误、系统崩溃以及可怕的“DLL   Hell”。另外,严格地写出所有这种附加代码,会降低开发人员的工作效率,导致延期上市。  
   
  这对使用Visual   C++&reg;开发系统的开发人员来说,尤其如此。而对使用Visual   Basic的开发人员来说,这种情况不是很严重。Visual   Basic抽象并简化了COM的许多概念,是全世界最具生产力、最流行的开发环境,但它的局限性在于:为了实现这种高生产力而不得不向开发人员屏蔽了COM的一些功能。  
   
  微软在2000年的专业开发人员大会(PDC)上引进的.NET框架,能自动在软件编写过程中进行“智能拼接”,使得开发人员可以集中精力编写业务逻辑,而不必编写COM基本结构。  
   
  什么是.NET框架?  
   
  .NET框架是一个多语言组件开发和执行环境,它由以下三个主要部分组成:  
   
   
  公共语言运行时。此名称不能准确反映它的全部功能。实际上,公共语言运行时在组件的开发及运行过程中,都扮演着非常重要的角色。在组件运行过程中,运行时负责管理内存分配、启动或删除线程和进程、实施安全性策略、同时满足当前组件对其它组件的需求。在开发阶段,运行时的作用有些变化:与现今的COM相比,运行时的自动化程度大为提高(比如可自动执行内存管理),因而开发人员的工作变得非常轻松。尤其是,映射功能将锐减开发人员将业务逻辑程序转化成可复用组件的代码编写量。对编程语言而言,运行时这个概念并不新奇:实际上每种编程语言都有自己的运行时。Visual   Basic开发系统具有最为明显的运行时(名为VBRUN),Visual   C++&reg;跟Visual   FoxPro&reg;、Jscript&reg;、SmallTalk、Perl、Python和Java一样有一个运行时,即MSVCRT。.NET框架的关键作用在于,它提供了一个跨编程语言的统一编程环境,这也是它能独树一帜的根本原因。    
   
  统一的编程类。.NET框架为开发人员提供了一个统一、面向对象、层次化、可扩展的类库集(API)。现今,C++开发人员使用的是Microsoft基类库,Java开发人员使用的是Windows&reg;基类库,而Visual   Basic用户使用的又是Visual   Basic   API集。只是简单地一用,.NET框架就统一了微软当前的各种不同类框架。这样,开发人员无需学习多种框架就能顺利编程。远不止于此的是,通过创建跨编程语言的公共API集,.NET框架可实现跨语言继承性、错误处理功能和调试功能。实际上,从JScript到C++的所有编程语言,都是相互等同的,开发人员可以自由选择理想的编程语言。    
   
  活动服务器页面(ASP+)。ASP+是使用.NET框架提供的编程类库构建而成的,它提供了Web应用程序模型,该模型由一组控件和一个基本结构组成。有了它,Web应用程序的构建变得非常容易。开发人员可以直接使用ASP+控件集,该控件集封装了公共的、用于超文本标识语言(HTML)用户界面的各种小器件(诸如文本框、下拉菜单等等)。实际上,这些控件运行在Web服务器上,它们将用户界面转换成HTML格式后再发送给浏览器。在服务器上,控件负责将面向对象的编程模型提供给Web开发人员,这种编程模型能提供面向对象编程技术的丰富功能。ASP+还提供一些基本结构服务(诸如会话状态管理和进程重启服务),这些服务大大减少了开发人员要编写的代码量,并使应用程序的可靠性得到大幅度提高。ASP+还允许开发人员将软件作为一项服务来提供。通过使用ASP+   Web服务功能,ASP+开发人员只需进行简单的业务逻辑编程,而由ASP+基本结构负责通过简单对象访问协议(SOAP)来提供服务。  
   
  与COM的关系  
   
  .NET框架的一个主要目的是使COM开发变得更加容易。COM开发过程中最难的一件事是处理COM基本结构。因此,为了简化COM开发,.NET框架实际上已自动处理了所有在开发人员看来是与“COM”紧密相关的任务,包括引用计算、接口描述以及注册。  
   
  必须认识到,这并不意味着.NET框架组件不是COM组件。事实上,使用Visual   Studio   6.0的COM开发人员可以调用.NET框架组件,并且在他们看来,后者更像是拥有iUnknown数据的COM组件。相反,使用Visual   Studio.NET的.NET框架开发人员则将COM组件视作.NET框架组件。  
   
  为了避免引起误解,这里需对这种关系加以特别说明:COM开发人员必须手动去做大多数.NET框架开发人员可以在运行时自动执行的事情。例如,必须手写COM组件的安全性模块,且无法自动管理模块占用的内存,而在安装COM组件时,注册条目必须放进Windows注册表中。对.NET框架而言,运行时实现了这些功能的自动化。例如,组件本身是自我描述型的,因而无需注册到Windows注册表中便能安装。  
   
  与COM+的关系  
   
  当把COM与Microsoft事务服务器(MTS)和分布式COM(DCOM)结合在一起时,就变成了COM+。COM+提供了一组面向中间层的服务。特别是COM+提供了进程管理功能和数据库与对象连接池处理功能。在将来的版本中,它还将提供一种称为分区的功能——专门为应用程序服务提供商设计的更强大的进程隔离功能。  
   
  COM+服务主要面向中间层应用程序开发,并主要为大型分布式应用程序提供可靠性和可扩展性。这些服务是对.NET框架所提供服务的补充;通过.NET框架类,可以直接访问这些服务。  

++++++++++
学习PEAA : Patterns Of Enterprise Application Architecture  

PEAA整理参考(持续)

Posted on 2007-10-27 14:40 sharplife 阅读(41) 评论(0)  编辑  收藏 所属分类: Agile dev

重读PEAA,把其提到的模式整理一下,方便参考

领域逻辑模式

事务脚本(Transaction script)
    使用过程来组织业务逻辑,每个过程处理来自表现层的单个请求

表模块(Table Module)
    处理某一数据库表或视图中所有行的业务逻辑的一个实例

领域模型(Domain Module)
    合并了行为和数据的领域的对象模型

服务层(Service Layer)
    通过一个服务层来定义应用程序边界,在服务层中建立一组可用的操作集合,并在每个操作内部协调应用程序的响应

数据源架构模式

表数据入口(Table Data Gateway)
    充当数据库表访问入口的对象,一个实例处理表中的所有的行

行数据入口(Row Data Gateway)
    充当数据库中单条记录入口的对象,每行一个实例

活动记录(Active Record)
    一个对象,它包括数据库表或视图的某一行,封装数据库访问,并在这些数据上增加了业务逻辑

数据库映射器(Data Mapper)
    在保持对象和数据库(以及映射器本身)彼此独立的情况下在二者之间移动数据的一个映射器

对象-关系行为模式

工作单元(Unit of Work)
    维护受业务事务影响的对象列表,并协调变化的写入和并发问题的解决

对象-关系结构模式


对象-关系元数据映射模式


Web表现模式

MVC模式
把用户界面交互分拆到三种不同角色中

页面控制器(Page Controller)
    在Web为特定页面或动作处理请求的对象

前端控制器(Front Controller)
    为Web站点处理所有请求的控制器,易于集中控制、易于抽象和装饰

模板视图(Template View)
    在html页面嵌入标记用于response信息

转换视图(Transform View)
    一项项处理领域逻辑,并将其转化成html的视图

两步视图(Two step View)
    先形成逻辑页面,在转换成html页面

应用控制器(Application Controller)
    应于处理屏幕导航和应用程序流的集中控制器,适于复杂的屏幕逻辑需求

分布模式

远程外观(Remote Facade)
    为细粒度对象提供粗粒度的外观用来改善网络上的效率,而服务层未必需要粗粒度封装

数据传输对象(Data Transfer Object)
    一个为了减少方法调用次数而在进程间传输数据的对象,有单一
/多个(细分)的选择

离线并发模式


会话状态模式

客户会话状态(Client State)
    将会话状态保存在客户端

服务端会话状态(Server State)
    将会话状态以序列化的方式存放在服务端

数据库会话状态(DataBase State)
    将会话数据作为已提交的数据保存到数据库中

基本模式

入口(Gateway)
    Client用于封装外部系统或者资源访问的对象,而Facade通常由服务作者提供,用于简化服务API

映射器(Mapper)
    在两个独立的对象间通信的对象,通常于层间,如数据库映射器
    Mediator解藕个对象间关系,但各对象知晓Mediator本身的存在,映射器不为任一子系统所知晓

层超类(Layer Supertype)
    某一类型充当一层中所有类型的超类

分离接口
    在一个包中定义接口,在另外一个与这个包分离的包中实现接口

注册表(Registry)
    一个众所周知的对象,其他对象可以通过该对象公共的对象的服务,如 Facade Session

值对象(Value Object)
    一个如货币或日期这样的小而简单的对象,判等时不根据标识ID,如.NET的struct类型
    注:j2ee社区使用此名称表示数据传输对象

货币(Money)
    表示一个货币值

特殊情况(Special Case)
    对特殊情况提供特殊行为的子类,如Employee实现的NULLEmployee

插件(Plugin)
    在配置时而非编译时链接类,结合工厂、接口、单体的插件实现

    plugin.JPG

                                例图

interface IdGenerator... 
        public static final IdGenerator INSTANCE =
               (IdGenerator) PluginFactory.getPlugin(IdGenerator.class);
 

服务桩(Service Stub)

       在测试时移除对具体服务的依赖,定义入口,以插件方式载入入口的实现,保持服务桩简单

       srvstub.JPG
                                图中Tax Service interface即为Gateway

记录集(Recordset)

       表格数据在内存中的表现方式


整理持续中......
++++++

和一个公司技术总监的交流心得

交流结束之后,心里面想了很多,总结了以下几点:

1、对我个人来说,比较满意的项目:

建行招商管理系统(从学校出来工作之后,一个人完成第一个比较系统的、规范的小项目,客户比较满意 2004-04)

番禺交警综合信息网(开发asp这么久,第一次接触asp面向对象式的开发思路和DHTML,并在项目逐渐掌握这种技术,对个人asp技术来说是一个量到质的转变,对asp有了新的认识 。2004-08——2005-03)

中国贸易广州展览公司门户网站(这个项目是拖得比较久的一个项目了,项目开发过程中,比较全面的熟悉了ASP.NET(C#)的开发模式,在实践中更多的体会dowamish式架构的高效率,并能够在ASP.NET熟练使用C#开发和ADO.NET进行数据操作,总结了可以让自己使用的开发模式。2004-10——2005-03)

广州白云环卫局项目(这个项目是我们主管离开公司发展之后我们技术组的第一个项目,一个人完成了从需求整理、分析、文档编写、框架设计、编码、测试和售后支持,在对项目开发所需时间、开发过程中的不可预见因素有了新的认识,使自己对项目在宏观方面有了更好的把握。同时这个项目根据公司顾问反馈说客户很满意,在对方验收过程中基本上没有什么修改提出,这更增强了自己在担当更大任务方面的信心。2005-04)

2、文档的编写

文档的编写在一个项目管理方面还是很重要的,没有一个系统的需求分析文档和概要设计文档,几乎就不能够很好的管理好手下的项目组成员。也不能够很好的和上级领导沟通(只在项目进程上沟通是远远不够的)。同时对于一个项目经理来说,方案策划能力、需求分析能力、概要设计文档编写能力都是不可缺少。同时需要更好的理解其中各个方面的关系和侧重点。

方案策划是给客户看的,客户是否信赖我们,是否放心把一个项目交给我们来开发不仅要在跟客户交流中处理好彼此的关系,更需要有一个好的策划方案,让客户看了方案就可以明确的知道,我们的产品能够胜任客户在项目中的需要,在产品使用过程中,能够提高客户在相关方面的效率,让客户更好的在各个方面进行有效的沟通。

需求分析文档是处于概要设计和方案策划之间的文档。由项目经理来编写,其中涉及到项目在各个过程中的流程转向、各个流程之间的关系、注意事项、开发目的以及最终需要达到一种什么样的效果。

概要设计就主要是给开发人员来看的,这个非常重要,其中涉及程序的具体实现,也许这个超出了项目经理的工作范畴,但是在不完善的公司人员组成中,项目经理也应该能够做到这个原本是由系统分析员来编写的文档。

作为一个优秀的项目经理来说,我觉得以上几点应该是可以做到的。


+++++


posted @ 2008-01-30 21:37 Borcala 阅读(644) 评论(0) 编辑
Duwamish的初次学习
    只有注册用户登录后才能阅读该文。阅读全文
posted @ 2008-01-30 21:00 Borcala 阅读(44) 评论(0) 编辑
ERP实施流程-步骤
    只有注册用户登录后才能阅读该文。阅读全文
posted @ 2008-01-30 17:48 Borcala 阅读(34) 评论(0) 编辑
口诀在(初级)会计学习中的妙用
    只有注册用户登录后才能阅读该文。阅读全文
posted @ 2008-01-30 17:46 Borcala 阅读(21) 评论(0) 编辑
ASP.NET 常用的33种代码(转,收藏一下,以备后查)
ASP.NET 常用的33种代码(转,收藏一下,以备后查)

1. 打开新的窗口并传送参数:

  传送参数:

response.write("<script>window.open(’*.aspx?id="+this.DropDownList1.SelectIndex+"&id1="+...+"’)</script>")
  接收参数:

string a = Request.QueryString("id");
string b = Request.QueryString("id1");
  
2.为按钮添加对话框

Button1.Attributes.Add("onclick","return confirm(’确认?’)");
button.attributes.add("onclick","if(confirm(’are you sure...?’)){return true;}else{return false;}")
  
3.删除表格选定记录

int intEmpID = (int)MyDataGrid.DataKeys[e.Item.ItemIndex];
string deleteCmd = "DELETE from Employee where emp_id = " + intEmpID.ToString()
  
4.删除表格记录警告

private void DataGrid_ItemCreated(Object sender,DataGridItemEventArgs e)
{
 switch(e.Item.ItemType)
 {
  case ListItemType.Item :
  case ListItemType.AlternatingItem :
  case ListItemType.EditItem:
   TableCell myTableCell;
   myTableCell = e.Item.Cells[14];
   LinkButton myDeleteButton ;
   myDeleteButton = (LinkButton)myTableCell.Controls[0];
   myDeleteButton.Attributes.Add("onclick","return confirm(’您是否确定要删除这条信息’);");
   break;
  default:
   break;
 }

}
  
5.点击表格行链接另一页

private void grdCustomer_ItemDataBound(object sender, System.Web.UI.WebControls.DataGridItemEventArgs e)
{
 //点击表格打开
 if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
  e.Item.Attributes.Add("onclick","window.open(’Default.aspx?id=" + e.Item.Cells[0].Text + "’);");
}
  双击表格连接到另一页

  在itemDataBind事件中

if(e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
 string OrderItemID =e.item.cells[1].Text;
 ...
 e.item.Attributes.Add("ondblclick", "location.href=’../ShippedGrid.aspx?id=" + OrderItemID + "’");
}
  双击表格打开新一页

if(e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
 string OrderItemID =e.item.cells[1].Text;
 ...
 e.item.Attributes.Add("ondblclick", "open(’../ShippedGrid.aspx?id=" + OrderItemID + "’)");
}


6.表格超连接列传递参数

<asp:HyperLinkColumn Target="_blank" headertext="ID号" DataTextField="id" NavigateUrl="aaa.aspx?id=’
 <%# DataBinder.Eval(Container.DataItem, "数据字段1")%>’ & name=’<%# DataBinder.Eval(Container.DataItem, "数据字段2")%>’ />
  
7.表格点击改变颜色

if (e.Item.ItemType == ListItemType.Item ||e.Item.ItemType == ListItemType.AlternatingItem)
{
 e.Item.Attributes.Add("onclick","this.style.backgroundColor=’#99cc00’;
    this.style.color=’buttontext’;this.style.cursor=’default’;");
}
  写在DataGrid的_ItemDataBound里

if (e.Item.ItemType == ListItemType.Item ||e.Item.ItemType == ListItemType.AlternatingItem)
{
e.Item.Attributes.Add("onmouseover","this.style.backgroundColor=’#99cc00’;
   this.style.color=’buttontext’;this.style.cursor=’default’;");
e.Item.Attributes.Add("onmouseout","this.style.backgroundColor=’’;this.style.color=’’;");
}

  
8.关于日期格式

  日期格式设定

DataFormatString="{0:yyyy-MM-dd}"
  我觉得应该在itembound事件中

e.items.cell["你的列"].text=DateTime.Parse(e.items.cell["你的列"].text.ToString("yyyy-MM-dd"))
  
9.获取错误信息并到指定页面

  不要使用Response.Redirect,而应该使用Server.Transfer

  e.g

// in global.asax
protected void Application_Error(Object sender, EventArgs e) {
if (Server.GetLastError() is HttpUnhandledException)
Server.Transfer("MyErrorPage.aspx");

//其余的非HttpUnhandledException异常交给ASP.NET自己处理就okay了 :)
}
  Redirect会导致post-back的产生从而丢失了错误信息,所以页面导向应该直接在服务器端执行,这样就可以在错误处理页面得到出错信息并进行相应的处理

  
10.清空Cookie

Cookie.Expires=[DateTime];
Response.Cookies("UserName").Expires = 0
  
11.自定义异常处理

//自定义异常处理类
using System;
using System.Diagnostics;

namespace MyAppException
{
 /// <summary>
 /// 从系统异常类ApplicationException继承的应用程序异常处理类。
 /// 自动将异常内容记录到Windows NT/2000的应用程序日志
 /// </summary>
 public class AppException:System.ApplicationException
 {
  public AppException()
  {
   if (ApplicationConfiguration.EventLogEnabled)LogEvent("出现一个未知错误。");
  }

 public AppException(string message)
 {
  LogEvent(message);
 }

 public AppException(string message,Exception innerException)
 {
  LogEvent(message);
  if (innerException != null)
  {
   LogEvent(innerException.Message);
  }
 }

 //日志记录类
 using System;
 using System.Configuration;
 using System.Diagnostics;
 using System.IO;
 using System.Text;
 using System.Threading;

 namespace MyEventLog
 {
  /// <summary>
  /// 事件日志记录类,提供事件日志记录支持
  /// <remarks>
  /// 定义了4个日志记录方法 (error, warning, info, trace)
  /// </remarks>
  /// </summary>
  public class ApplicationLog
  {
   /// <summary>
   /// 将错误信息记录到Win2000/NT事件日志中
   /// <param name="message">需要记录的文本信息</param>
   /// </summary>
   public static void WriteError(String message)
   {
    WriteLog(TraceLevel.Error, message);
   }

   /// <summary>
   /// 将警告信息记录到Win2000/NT事件日志中
   /// <param name="message">需要记录的文本信息</param>
   /// </summary>
   public static void WriteWarning(String message)
   {
    WriteLog(TraceLevel.Warning, message);  
   }

   /// <summary>
   /// 将提示信息记录到Win2000/NT事件日志中
   /// <param name="message">需要记录的文本信息</param>
   /// </summary>
   public static void WriteInfo(String message)
   {
    WriteLog(TraceLevel.Info, message);
   }
   /// <summary>
   /// 将跟踪信息记录到Win2000/NT事件日志中
   /// <param name="message">需要记录的文本信息</param>
   /// </summary>
   public static void WriteTrace(String message)
   {
    WriteLog(TraceLevel.Verbose, message);
   }

   /// <summary>
   /// 格式化记录到事件日志的文本信息格式
   /// <param name="ex">需要格式化的异常对象</param>
   /// <param name="catchInfo">异常信息标题字符串.</param>
   /// <retvalue>
   /// <para>格式后的异常信息字符串,包括异常内容和跟踪堆栈.</para>
   /// </retvalue>
   /// </summary>
   public static String FormatException(Exception ex, String catchInfo)
   {
    StringBuilder strBuilder = new StringBuilder();
    if (catchInfo != String.Empty)
    {
     strBuilder.Append(catchInfo).Append("\r\n");
    }
    strBuilder.Append(ex.Message).Append("\r\n").Append(ex.StackTrace);
    return strBuilder.ToString();
   }

   /// <summary>
   /// 实际事件日志写入方法
   /// <param name="level">要记录信息的级别(error,warning,info,trace).</param>
   /// <param name="messageText">要记录的文本.</param>
   /// </summary>
   private static void WriteLog(TraceLevel level, String messageText)
   {
    try
    {
     EventLogEntryType LogEntryType;
     switch (level)
     {
      case TraceLevel.Error:
       LogEntryType = EventLogEntryType.Error;
       break;
      case TraceLevel.Warning:
       LogEntryType = EventLogEntryType.Warning;
       break;
      case TraceLevel.Info:
       LogEntryType = EventLogEntryType.Information;
       break;
      case TraceLevel.Verbose:
       LogEntryType = EventLogEntryType.SuccessAudit;
       break;
      default:
       LogEntryType = EventLogEntryType.SuccessAudit;
       break;
     }

     EventLog eventLog = new EventLog("Application", ApplicationConfiguration.EventLogMachineName, ApplicationConfiguration.EventLogSourceName );
     //写入事件日志
     eventLog.WriteEntry(messageText, LogEntryType);

    }
   catch {} //忽略任何异常
  }
 } //class ApplicationLog
}

12.Panel 横向滚动,纵向自动扩展

<asp:panel style="overflow-x:scroll;overflow-y:auto;"></asp:panel>
  
13.回车转换成Tab

<script language="javascript" for="document" event="onkeydown">
 if(event.keyCode==13 && event.srcElement.type!=’button’ && event.srcElement.type!=’submit’ &&     event.srcElement.type!=’reset’ && event.srcElement.type!=’’&& event.srcElement.type!=’textarea’);
   event.keyCode=9;
</script>

onkeydown="if(event.keyCode==13) event.keyCode=9"

  
14.DataGrid超级连接列

DataNavigateUrlField="字段名" DataNavigateUrlFormatString="http://xx/inc/delete.aspx?ID={0}"
  
15.DataGrid行随鼠标变色

private void DGzf_ItemDataBound(object sender, System.Web.UI.WebControls.DataGridItemEventArgs e)
{
 if (e.Item.ItemType!=ListItemType.Header)
 {
  e.Item.Attributes.Add( "onmouseout","this.style.backgroundColor=\""+e.Item.Style["BACKGROUND-COLOR"]+"\"");
  e.Item.Attributes.Add( "onmouseover","this.style.backgroundColor=\""+ "#EFF3F7"+"\"");
 }
}
  
16.模板列
www.knowsky.com

<ASP:TEMPLATECOLUMN visible="False" sortexpression="demo" headertext="ID">
<ITEMTEMPLATE>
<ASP:LABEL text=’<%# DataBinder.Eval(Container.DataItem, "ArticleID")%>’ runat="server" width="80%" id="lblColumn" />
</ITEMTEMPLATE>
</ASP:TEMPLATECOLUMN>

<ASP:TEMPLATECOLUMN headertext="选中">
<HEADERSTYLE wrap="False" horizontalalign="Center"></HEADERSTYLE>
<ITEMTEMPLATE>
<ASP:CHECKBOX id="chkExport" runat="server" />
</ITEMTEMPLATE>
<EDITITEMTEMPLATE>
<ASP:CHECKBOX id="chkExportON" runat="server" enabled="true" />
</EDITITEMTEMPLATE>
</ASP:TEMPLATECOLUMN>
  后台代码

protected void CheckAll_CheckedChanged(object sender, System.EventArgs e)
{
 //改变列的选定,实现全选或全不选。
 CheckBox chkExport ;
 if( CheckAll.Checked)
 {
  foreach(DataGridItem oDataGridItem in MyDataGrid.Items)
  {
   chkExport = (CheckBox)oDataGridItem.FindControl("chkExport");
   chkExport.Checked = true;
  }
 }
 else
 {
  foreach(DataGridItem oDataGridItem in MyDataGrid.Items)
  {
   chkExport = (CheckBox)oDataGridItem.FindControl("chkExport");
   chkExport.Checked = false;
  }
 }
}
  
17.数字格式化

  【<%#Container.DataItem("price")%>的结果是500.0000,怎样格式化为500.00?】

<%#Container.DataItem("price","{0:¥#,##0.00}")%>

int i=123456;
string s=i.ToString("###,###.00");

18.日期格式化

  【aspx页面内:<%# DataBinder.Eval(Container.DataItem,"Company_Ureg_Date")%>

  显示为: 2004-8-11 19:44:28

  我只想要:2004-8-11 】

<%# DataBinder.Eval(Container.DataItem,"Company_Ureg_Date","{0:yyyy-M-d}")%>
  应该如何改?

  【格式化日期】

  取出来,一般是object((DateTime)objectFromDB).ToString("yyyy-MM-dd");

  【日期的验证表达式】

  A.以下正确的输入格式: [2004-2-29], [2004-02-29 10:29:39 pm], [2004/12/31]

^((\d{2}(([02468][048])|([13579][26]))[\-\/\s]?((((0?[13578])|(1[02]))[\-\/\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\-\/\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\-\/\s]?((0?[1-9])|([1-2][0-9])))))|(\d{2}(([02468][1235679])|([13579][01345789]))[\-\/\s]?((((0?[13578])|(1[02]))[\-\/\s]?((0?[1-9])|([1-2][0-9])|(3[01])))|(((0?[469])|(11))[\-\/\s]?((0?[1-9])|([1-2][0-9])|(30)))|(0?2[\-\/\s]?((0?[1-9])|(1[0-9])|(2[0-8]))))))(\s(((0?[1-9])|(1[0-2]))\:([0-5][0-9])((\s)|(\:([0-5][0-9])\s))([AM|PM|am|pm]{2,2})))?$
  B.以下正确的输入格式:[0001-12-31], [9999 09 30], [2002/03/03]

^\d{4}[\-\/\s]?((((0[13578])|(1[02]))[\-\/\s]?(([0-2][0-9])|(3[01])))|(((0[469])|(11))[\-\/\s]?(([0-2][0-9])|(30)))|(02[\-\/\s]?[0-2][0-9]))$
  【大小写转换】

HttpUtility.HtmlEncode(string);
HttpUtility.HtmlDecode(string)
  
19.如何设定全局变量

  Global.asax中

  Application_Start()事件中

  添加Application[属性名] = xxx;

  就是你的全局变量

  
20.怎样作到HyperLinkColumn生成的连接后,点击连接,打开新窗口?

  HyperLinkColumn有个属性Target,将器值设置成"_blank"即可.(Target="_blank")

  【ASPNETMENU】点击菜单项弹出新窗口

  在你的menuData.xml文件的菜单项中加入URLTarget="_blank",如:

<?xml version="1.0" encoding="GB2312"?>
<MenuData ImagesBaseURL="images/">
<MenuGroup>
<MenuItem Label="内参信息" URL="Infomation.aspx" >
<MenuGroup ID="BBC">
<MenuItem Label="公告信息" URL="Infomation.aspx" URLTarget="_blank" LeftIcon="file.gif"/>
<MenuItem Label="编制信息简报" URL="NewInfo.aspx" LeftIcon="file.gif" />
......
  最好将你的aspnetmenu升级到1.2版

  
21.读取DataGrid控件TextBox值

foreach(DataGrid dgi in yourDataGrid.Items)
{
 TextBox tb = (TextBox)dgi.FindControl("yourTextBoxId");
 tb.Text....
}
  
23.在DataGrid中有3个模板列包含Textbox分别为 DG_ShuLiang (数量) DG_DanJian(单价) DG_JinE(金额)分别在5.6.7列,要求在录入数量及单价的时候自动算出金额即:数量*单价=金额还要求录入时限制为 数值型.我如何用客户端脚本实现这个功能?

  〖思归〗

<asp:TemplateColumn HeaderText="数量">
<ItemTemplate>
<asp:TextBox id="ShuLiang" runat=’server’ Text=’<%# DataBinder.Eval(Container.DataItem,"DG_ShuLiang")%>’
onkeyup="javascript:DoCal()"
/>

<asp:RegularExpressionValidator id="revS" runat="server" ControlToValidate="ShuLiang" ErrorMessage="must be integer" ValidationExpression="^\d+$" />
</ItemTemplate>
</asp:TemplateColumn>

<asp:TemplateColumn HeaderText="单价">
<ItemTemplate>
<asp:TextBox id="DanJian" runat=’server’ Text=’<%# DataBinder.Eval(Container.DataItem,"DG_DanJian")%>’
onkeyup="javascript:DoCal()"
/>

<asp:RegularExpressionValidator id="revS2" runat="server" ControlToValidate="DanJian" ErrorMessage="must be numeric" ValidationExpression="^\d+(\.\d*)?$" />

</ItemTemplate>
</asp:TemplateColumn>

<asp:TemplateColumn HeaderText="金额">
<ItemTemplate>
<asp:TextBox id="JinE" runat=’server’ Text=’<%# DataBinder.Eval(Container.DataItem,"DG_JinE")%>’ />
</ItemTemplate>
</asp:TemplateColumn><script language="javascript">
function DoCal()
{
 var e = event.srcElement;
 var row = e.parentNode.parentNode;
 var txts = row.all.tags("INPUT");
 if (!txts.length || txts.length < 3)
  return;

 var q = txts[txts.length-3].value;
 var p = txts[txts.length-2].value;

 if (isNaN(q) || isNaN(p))
  return;

 q = parseInt(q);
 p = parseFloat(p);

 txts[txts.length-1].value = (q * p).toFixed(2);
}
</script>


24.datagrid选定比较底下的行时,为什么总是刷新一下,然后就滚动到了最上面,刚才选定的行因屏幕的关系就看不到了。

page_load
page.smartNavigation=true
  
25.在Datagrid中修改数据,当点击编辑键时,数据出现在文本框中,怎么控制文本框的大小 ?

private void DataGrid1_ItemDataBound(obj sender,DataGridItemEventArgs e)
{
 for(int i=0;i<e.Item.Cells.Count-1;i++)
  if(e.Item.ItemType==ListItemType.EditType)
  {
   e.Item.Cells[i].Attributes.Add("Width", "80px")
  }
}
  
26.对话框

private static string ScriptBegin = "<script language=\"JavaScript\">";
private static string ScriptEnd = "</script>";

public static void ConfirmMessageBox(string PageTarget,string Content)
{
 string ConfirmContent="var retValue=window.confirm(’"+Content+"’);"+"if(retValue){window.location=’"+PageTarget+"’;}";

 ConfirmContent=ScriptBegin + ConfirmContent + ScriptEnd;

 Page ParameterPage = (Page)System.Web.HttpContext.Current.Handler;
 ParameterPage.RegisterStartupScript("confirm",ConfirmContent);
 //Response.Write(strScript);
}
  
27. 将时间格式化:
string aa=DateTime.Now.ToString("yyyy年MM月dd日");

  1.1 取当前年月日时分秒

currentTime=System.DateTime.Now;
  1.2 取当前年

int 年= DateTime.Now.Year;
  1.3 取当前月

int 月= DateTime.Now.Month;
  1.4 取当前日

int 日= DateTime.Now.Day;
  1.5 取当前时

int 时= DateTime.Now.Hour;
  1.6 取当前分

int 分= DateTime.Now.Minute;
  1.7 取当前秒

int 秒= DateTime.Now.Second;
  1.8 取当前毫秒

int 毫秒= DateTime.Now.Millisecond;
  
28.自定义分页代码:

  先定义变量 :

public static int pageCount; //总页面数
public static int curPageIndex=1; //当前页面
  下一页:

if(DataGrid1.CurrentPageIndex < (DataGrid1.PageCount - 1))
{
 DataGrid1.CurrentPageIndex += 1;
 curPageIndex+=1;
}

bind(); // DataGrid1数据绑定函数
  上一页:

if(DataGrid1.CurrentPageIndex >0)
{
 DataGrid1.CurrentPageIndex += 1;
 curPageIndex-=1;
}

bind(); // DataGrid1数据绑定函数
  直接页面跳转:

int a=int.Parse(JumpPage.Value.Trim());//JumpPage.Value.Trim()为跳转值

if(a<DataGrid1.PageCount)
{
 this.DataGrid1.CurrentPageIndex=a;
}

bind();

29.DataGrid使用:

  添加删除确认:

private void DataGrid1_ItemCreated(object sender, System.Web.UI.WebControls.DataGridItemEventArgs e)
{
 foreach(DataGridItem di in this.DataGrid1.Items)
 {
  if(di.ItemType==ListItemType.Item||di.ItemType==ListItemType.AlternatingItem)
  {
   ((LinkButton)di.Cells[8].Controls[0]).Attributes.Add("onclick","return confirm(’确认删除此项吗?’);");
  }
 }
}
  样式交替:

ListItemType itemType = e.Item.ItemType;

if (itemType == ListItemType.Item )
{
 e.Item.Attributes["onmouseout"] = "javascript:this.style.backgroundColor=’#FFFFFF’;";
 e.Item.Attributes["onmouseover"] = "javascript:this.style.backgroundColor=’#d9ece1’;cursor=’hand’;" ;
}
else if( itemType == ListItemType.AlternatingItem)
{
 e.Item.Attributes["onmouseout"] = "javascript:this.style.backgroundColor=’#a0d7c4’;";
 e.Item.Attributes["onmouseover"] = "javascript:this.style.backgroundColor=’#d9ece1’;cursor=’hand’;" ;
}
  添加一个编号列:

DataTable dt= c.ExecuteRtnTableForAccess(sqltxt); //执行sql返回的DataTable
DataColumn dc=dt.Columns.Add("number",System.Type.GetType("System.String"));

for(int i=0;i<dt.Rows.Count;i++)
{
 dt.Rows[i]["number"]=(i+1).ToString();
}

DataGrid1.DataSource=dt;
DataGrid1.DataBind();
  DataGrid1中添加一个CheckBox,页面中添加一个全选框

private void CheckBox2_CheckedChanged(object sender, System.EventArgs e)
{
 foreach(DataGridItem thisitem in DataGrid1.Items)
 {
  ((CheckBox)thisitem.Cells[0].Controls[1]).Checked=CheckBox2.Checked;
 }
}
  将当前页面中DataGrid1显示的数据全部删除

foreach(DataGridItem thisitem in DataGrid1.Items)
{
 if(((CheckBox)thisitem.Cells[0].Controls[1]).Checked)
 {
  string strloginid= DataGrid1.DataKeys[thisitem.ItemIndex].ToString();
  Del (strloginid); //删除函数
 }
}
  
30.当文件在不同目录下,需要获取数据库连接字符串(如果连接字符串放在Web.config,然后在Global.asax中初始化)

  在Application_Start中添加以下代码:

Application["ConnStr"]=this.Context.Request.PhysicalApplicationPath+ConfigurationSettings.
   AppSettings["ConnStr"].ToString();
  
31. 变量.ToString()

  字符型转换 转为字符串

12345.ToString("n"); //生成 12,345.00
12345.ToString("C"); //生成 ¥12,345.00
12345.ToString("e"); //生成 1.234500e+004
12345.ToString("f4"); //生成 12345.0000
12345.ToString("x"); //生成 3039 (16进制)
12345.ToString("p"); //生成 1,234,500.00%
  
32、变量.Substring(参数1,参数2);

  截取字串的一部分,参数1为左起始位数,参数2为截取几位。 如:string s1 = str.Substring(0,2);

  
33.在自己的网站上登陆其他网站:(如果你的页面是通过嵌套方式的话,因为一个页面只能有一个FORM,这时可以导向另外一个页面再提交登陆信息)

<SCRIPT language="javascript">
<!--
 function gook(pws)
 {
  frm.submit();
 }
//-->

</SCRIPT> <body leftMargin="0" topMargin="0" onload="javascript:gook()" marginwidth="0" marginheight="0">
<form name="frm" action=" http://220.194.55.68:6080/login.php?retid=7259 " method="post">
<tr>
<td>
<input id="f_user" type="hidden" size="1" name="f_user" runat="server">
<input id="f_domain" type="hidden" size="1" name="f_domain" runat="server">
<input class="box" id="f_pass" type="hidden" size="1" name="pwshow" runat="server">

<INPUT id="lng" type="hidden" maxLength="20" size="1" value="5" name="lng">
<INPUT id="tem" type="hidden" size="1" value="2" name="tem">

</td>

</tr>

</form>
  文本框的名称必须是你要登陆的网页上的名称,如果源码不行可以用vsniffer 看看。

  下面是获取用户输入的登陆信息的代码:

string name;
name=Request.QueryString["EmailName"];

try
{
 int a=name.IndexOf("@",0,name.Length);
 f_user.Value=name.Substring(0,a);
 f_domain.Value=name.Substring(a+1,name.Length-(a+1));
 f_pass.Value=Request.QueryString["Psw"];
}

catch
{
 Script.Alert("错误的邮箱!");
 Server.Transfer("index.aspx");
}


转自:动态网制作指南 www.knowsky.com

posted on 2007-11-29 10:14 教书愚人 毁人不倦 阅读(158) 评论(1)  编辑  收藏 所属分类: dotnet技术
posted @ 2008-01-30 01:30 Borcala 阅读(147) 评论(1) 编辑
Copyright ©2012 Borcala