Archive for the ‘计算机科学与技术’ Category
新发现的一个好东西 Script#
Script# 就是一个用 C# 代码来写脚本语言,然后通过特定的编译器将其转换成 Javascript。
不想在我这里说太多,作者的 blog 上面已经写的很清楚了。
有兴趣的可以到这里看一下。
另外还觉得这个东西生成的 Javascript 所引进的面向对象模型有点意思,等我研究一下再来说说。
偶然间发现一个 PI 的算法
long a = 10000, b = 0, c = 2800, d, e = 0, f[2801], g;
main() {
for (; b - c; ) f[b++] = a / 5;
for (; d = 0, g = c * 2; c -= 14, printf("%.4d", e + d / a), e = d % a);
for (b = c; d += f[b] * a, f[b] = d % --g, d /= g--, --b; d *= b);
}
结果是
5926 5358 9793 2384 6264 3383 2795 0288 4197 1693 9937 5105 8209 7494 4592 3078 1640 6286 2089 9862 8034 8253 4211 7067 9821 4808 6513 2823 0664 7093 8446 0955 0582 2317 2535 9408 1284 8111 7450 2841 0270 1938 5211 0555 9644 6229 4895 4930 3819 6442 8810 9756 6593 3446 1284 7564 8233 7867 8316 5271 2019 0914 5648 5669 2346 0348 6104 5432 6648 2133 9360 7260 2491 4127 3724 5870 0660 6315 5881
CS0013 or CS0016 Compilation Errors in ASP.NET Web Applications
SYMPTOMS
When you view a Microsoft ASP.NET Application in a Web browser, you may receive the following error messages:
For the Microsoft .NET Framework version 1.1, the error message is the following:
CS0016: Could not write to output file 'c:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\Temporary
ASP.NET Files\application1\c11b43f6\cf3ec03\rizcntet.dll' . The directory name is invalid.
For the .NET Framework 1.0, the error message is the following:
CS0013: Unexpected error writing metadata to file
'C:\WINDOWS\Microsoft.NET\Framework\v1.0.3705\Temporary ASP.NET Files\application2\3fc72f26\eb731247\ev2bslce.dll'.
The directory name is invalid.
CAUSE
The system TEMP and TMP variables point to a folder that does not exist.
The compiler generates temporary files in the folder where the TEMP and the TMP variables point to before the files are copied to the Temporary ASP.NET Files folder. However, the folder where the system variables point to is deleted when you restart the computer. Therefore, the compiler cannot generate the temporary files.
RESOLUTION
- Create a temporary folder under %Systemroot%, and then name it Temp.
- Grant full permissions on the Temp folder to the aspnet user account in .NET Framework 1.0 or to the NETWORK SERVICE user account in .NET Framework 1.1.
- Right-click My Computer, and then click Properties.
- On the Advanced tab, click Environment Variables.
- Select the TEMP variable under System variables, and then click Edit.
- Type %SystemRoot%\TEMP in the Variable Value box, and then click OK.
- Repeat steps 5 and 6 to edit the TMP variable. Click OK two times.
- Click Start, and then click Run.
- To reset Internet Information Services (IIS), type iisreset on the command prompt.
Note If the error message that is mentioned in the "Symptoms" section of this article persists, restart the computer.
MORE INFORMATION
Steps to Reproduce the Behavior
- Start Microsoft Visual Studio .NET.
- Create a new ASP.NET Web Application project by using Microsoft Visual C# .NET or Microsoft Visual Basic .NET, and then name the project CompileTest.
- On the Build menu, click Build Solution.
- Right-click My Computer, and then click Properties.
- On the Advanced tab, click Environment Variables.
- Select the TEMP variable under System variables,
and then click Edit. - Type %SystemRoot%\TEMP1 in the Variable Value box to point to the nonexistent TEMP1 folder, and then click OK.
- 8.Repeat steps 6 and 7 to edit the TMP variable to point to the nonexistent TEMP1 folder.
- 9.Click OK two times.
- 10.To notice one of the error messages that are mentioned in the "Symptoms" section of this article, visit the following URL: http://localhost/CompileTest/WebForm1.aspx
Hermite 曲线的算法与实现
摘要:本文主要介绍了一种自由曲线 Hermite 曲线的数学原理,并以此为依据构造了 Hermite 曲线的计算机算法,并在微软的 .net 框架下使用 GDI+ 实现。
关键字:合成曲线,Hermite曲线,C#,GDI+
一、数学原理
曲线是构建几何模型的最基本元素之一,主要分为解析曲线和合成曲线。解析曲线通常是先有曲线方程,然后才能把曲线画出来,这种方式对于曲线的构造者来说是非常复杂且不直观的,而且改变曲线的一些参数,设计者也无法立刻了解曲线形状会做怎样的变化。在作曲线设计时,设计者通常希望能先将大致形状用很直观的方式描绘出来,并能够很容易的依照所需要的形状作修改,因此合成曲线是比较合适的方式。
合成曲线通常以参数的形式来表现,是由设计者根据其设计的需求和几何信息,去“合成”出这条曲线。这样由设计者输入的几何数据,就是曲线的控制点。
一般的合成曲线,至少需要一个三次的参数式:
公式(1)
用向量表示为:
公式(2)
如何确定式中的参数,就形成了不同的合成曲线的构造方法。Hermite 曲线就是通过曲线的起点(P0)、终点(P1)、起点切向量(V0)和终点切向量(V1)来确定曲线的。改变这四个参数,就可以控制 Hermite 曲线的形状。图1就是构建 Hermite 曲线的示意图。
图1
当给定以上四个参数之后,如何来确定这条 Hermite 曲线呢?
首先将(2)式作一次微分得到:
公式(3)
然后将 u=0,u=1 代入(2)式和(3)式中,就可以得到参数式中的系数:
公式(4)
将(4)式作进一步整理,最后可以将 Hermite 曲线方程写成如下形式:
公式(5)
这就是 Hermite 曲线的参数方程。根据此方程,对于 P0=(-2,2),P1=(3,-1),V0=(8,10) 和 V1=(15,10) 这四个参数,可以构造如下的表格:
使用 Matlab 绘制此曲线,得到图2:
图2
但是在做曲线设计时,Hermite 曲线仍然存在不少问题,例如在建立 Hermite 曲线时设计者必须输入曲线两端切向量的大小和方向,这对设计者来讲仍然是不直观的。另外,Hermite 曲线不具有区域控制的能力,在建立 Hermite 曲线时提供的是个参数,改变任何一项输入,整条曲线的形状都会发生变化,设计者很难对其进行局部的、小范围的修改。
二、算法
有了以上的数学基础,构造算法就不是件困难的事情。
/// <summary>
/// 绘制Hermite曲线的核心方法
/// </summary>
/// <param name="pen">绘制曲线用的Pen对象</param>
/// <param name="p0">起点坐标</param>
/// <param name="p1">终点坐标</param>
/// <param name="v0">起点切向量</param>
/// <param name="v1">终点切向量</param>
private void DrawHermite(Pen pen,Point p0, Point p1, Point v0, Point v1) {
// 计算出来的当前坐标
int x = p0.X;
int y = p0.Y;
// 计算出来的前一个坐标,使用该两个做标连成一条线,来绘制曲线
int preX, preY;
// 根据参数计算每个点的坐标,参数的增量为0.01
for (double i = 0.0; i <= 1.0; i = i + 0.01) {
preX = x;
preY = y;
// 保存计算中间结果,避免重复计算,提高算法效率
double i2 = i * i;
double i3 = i2 * i;
double express = 3 * i2 - 2 * i3;
// 计算横坐标和纵坐标
x = (int)((1 - express) * p0.X + express * p1.X + (i - 2 * i2 + i3) * v0.X + (i3 - i2) * v1.X);
y = (int)((1 - express) * p0.Y + express * p1.Y + (i - 2 * i2 + i3) * v0.Y + (i3 - i2) * v1.Y);
// 画线
this.drawingSurface.DrawLine(pen, preX, preY, x, y);
}
this.drawingSurface.DrawLine(pen, x, y, p1.X, p1.Y);
}
三、使用 GDI+ 实现
在 .net 框架下,使用 GDI+ 实现这个算法是件轻松的事情。但是在编程过程中仍然出现了几个问题。
首先,如何确定两个起点和两个切向量。本程序采用了如下的方法:先选定一个点,然后拉出一条直线,以该点为起点(或终点)并以该直线的方向和长度作为起点(或终点)切向量的方向和大小。
其次,本程序可以实现类似 PhotoShop 中的钢笔功能。所以有一个如何产生拉动的效果的问题。这对这个问题使用了两种不同的解决方法:1、对于画曲线,使用了两个画笔,一个用于绘制,一个用于擦除。当鼠标移动的时候,就会使用绘制的画笔绘制新曲线,并用擦除画笔擦除刚才的曲线。但该方法会导致另一个问题,就是当该曲线覆盖到其他线条上之后,当曲线离开后,该线条就会有部分被擦掉。但是想解决这个问题是很困难的。(不知道 PhotoShop 是如何实现的。)2、画直线的时候,使用了 GDI+ 中自带的一个 ControlPaint.DrawReversibleLine() 方法,该方法可以自己解决以上的问题。
第三、像这样一遍一遍的重画和擦除,会很占用系统资源,但是没有什么更好的解决方法,从网上找到的文章来看,如果复写(Override)OnMouseDown, OnMouseMove 和 OnMouseUp 事件,会比处理此三个事件的方法要来得效率高一些,因此本程序的所有事件全部采用了这种方法。下面的这段代码,是复写了 OnMouseMove 事件,用于处理当鼠标按下左键移动的时候,产生的拉动效果。
protected override void OnMouseMove(MouseEventArgs e) {
// 判断当鼠标移动的时候是否有鼠标左键按下
if (e.Button == MouseButtons.Left) {
// isContinuedDrawing 是个标志变量,标志所产时的动作是否为了画第二个参量
if (!isContinedDrawing) {
endPoint[0].X = e.X;
endPoint[0].Y = e.Y;
// 使用 ControlPaint 画直线
ControlPaint.DrawReversibleLine(PointToScreen(startPoint[0])PointToScreen(previousPoint), Color.Black);
ControlPaint.DrawReversibleLine(PointToScreen(startPoint[0]), PointToScreen(endPoint[0]), Color.Black);
previousPoint = endPoint[0];
} else {
endPoint[1].X = e.X;
endPoint[1].Y = e.Y; ControlPaint.DrawReversibleLine(PointToScreen(startPoint[1]), PointToScreen(previousPoint), Color.Black);
Point _v0 = new Point();
_v0.X = endPoint[0].X - startPoint[0].X;
_v0.Y = endPoint[0].Y - startPoint[0].Y;
Point _v1 = new Point();
_v1.X = previousPoint.X - startPoint[1].X;
_v1.Y = previousPoint.Y - startPoint[1].Y;
// 擦除以前的曲线
this.DrawHermite(erasePen,startPoint[0], startPoint[1], _v0, _v1);
// 画新的曲线
ControlPaint.DrawReversibleLine(PointToScreen(startPoint[1]), PointToScreen(endPoint[1]), Color.Black);
_v1.X = endPoint[1].X - startPoint[1].X;
_v1.Y = endPoint[1].Y - startPoint[1].Y;
this.DrawHermite(drawPen,startPoint[0], startPoint[1], _v0, _v1);
previousPoint = endPoint[1];
}
}
// 调用父类中的 OnMouseOver 事件三
base.OnMouseMove(e);
}
四、程序截图
五、参考文献
- 台湾元智大學機械系大三機械設計課程教材
- 使用 .net 框架绘制橡皮条带
【zz】History of the Graphical User Interface
The graphical user interface, or "GUI", is a computer interface that uses graphic icons and controls in addition to text. The user of the computer utilizes a pointing device, like a mouse, to manipulate these icons and controls. This was a great leap forward from the command line interface used in other operating systems, in which the user types a series of text commands to the computer.
Initial Developments
The first concept of a windowing system begins with the first real-time graphic display systems for computers, namely the SAGE Project and Ivan Sutherland’s Sketchpad.
Augmentation of Human Intellect
Doug Engelbart’s Augmentation of Human Intellect project at SRI in the 1960s developed the On-Line System, which incorporated a mouse-driven cursor and multiple windows.
Xerox PARC
Engelbart’s work directly led to the advances at Xerox PARC. Several people went from SRI to Xerox PARC in the early 1970’s. The Xerox PARC team codified the WIMP (windows, icons, menus and pointers/pull-down menus) paradigm, first pioneered on the Xerox Alto experimental computer, but which eventually appeared commercially in the Xerox 8010 ("Star") system in 1981.
Apple Lisa and Macintosh
Beginning in 1979, led by Jef Raskin, the Lisa and Macintosh teams at Apple Computer (which included former members of the Xerox PARC group) continued to develop such ideas. The Macintosh, released in 1984, was the first commercially successful product to use a GUI. A desktop metaphor was used, in which files looked like pieces of paper; directories looked like file folders; there were a set of desk accessories like a calculator, notepad, and alarm clock that the user could place around the screen as desired; and the user could delete files and folders by dragging them to a trash can on the screen.
There is still some controversy over the amount of influence that Xerox’s PARC work, as opposed to previous academic research, had on the GUIs of Apple’s Lisa and Macintosh, but it is clear that the influence was extensive.
The Macintosh’s GUI has been revised with time since 1984, with a major update with System 7, and underwent its largest revision with the introduction of the "Aqua" interface in 2001’s Mac OS X.
VisiOn
Graphical user interface primarily designed for spreadsheets by the company that wrote the legendary VisiCalc spreadsheet. First introduced the "windows" concept and a mouse to the PC environment, in 1983. Preceded the first Microsoft Windows implementations. VisiOn never took off because it could not be used to run other MS-DOS applications and was buggy and expensive. Inspired the multitasking system DESQview.
Amiga Intuition
Amiga computers developed a GUI in 1985 called Intuition. In this GUI directories were shown as filing cabinet drawers.
The Amiga GUI was unique for its time because it featured a pop-up command line interface (CLI) for those times when a GUI does not offer enough control.
GEM
At the same time Microsoft was developing Windows in the 1980s, Digital Research developed the GEM Desktop GUI system. GEM was created as an alternative window system to run on IBM PC systems, either on top of MS-DOS (like Microsoft Windows) or on top of CPM-86, DR’s own operating system that MS-DOS was patterened after. GEM achieved minimal success in the PC world, but was later used as the native GUI on the Atari ST machines.
GEOS
GEOS was another very early graphical desktop system. Originally written for the 8 bit home computer Commodore 64 it was later ported to IBM PC systems. It came with several application programs like a calendar and word processor, and a cut-down version served as the basis for America Online’s DOS client. Compared to the competing Windows 3.0 GUI, it could run reasonably well on simpler hardware.
Revivals were seen in the HP OmniGo handhelds, Brother GeoBook line of laptop-appliances, and the New Deal Office package for PCs. Related code found its way to earlier ’Zoomer’ PDAs, creating an unclear lineage to Palm, Inc’s later work.
Microsoft Windows
Microsoft modeled the first version of Windows, released in 1985, on the GUI of the Mac OS. Windows 1.0 was a GUI (graphic user interface) for the MS-DOS operating system that had been the standard OS for with IBM PC and compatible computers since 1981. Windows 2.0 followed, then in 1990 the Windows 3.0 launch was when the popularity of Windows really exploded. The GUIs of subsequent versions of Windows have been similar to the GUI of Windows 3.0.
In 1988, Apple sued Microsoft for copyright infringement of the Lisa and Apple Macintosh GUI. The court case lasted 4 years before almost all of Apple’s claims were denied. Subsequent appeals by Apple were also denied, and Microsoft and Apple apparently entered a final, private settlement of the matter in 1997 as a side note in a broader announcement of investment and cooperation.
RISC OS
Early versions of what became called RISC OS were known as Arthur, which was released in 1987. RISC OS was a colour GUI operating system which used three-buttoned mice, a taskbar (called the iconbar), and a file navigator similar to that of Mac OS. Acorn created RISC OS in the 1980s for their ARM-CPU based computers.
NeXTSTEP
The NeXTSTEP user interface was used in the NeXT line of computers. NeXTSTEP’s first major version was released in 1989. It used Display PostScript for its graphical underpinning. The NeXTSTEP interface’s most significant feature was the Dock, carried into Mac OS X, and had other minor interface details that some found made it easier and more intuitive to use than previous GUIs. NeXTSTEP’s GUI was the first to feature opaque dragging of windows in its user interface, on a comparatively weak machine by today’s standards.
Originally collaboratively developed by Microsoft and IBM to replace DOS, version 1.0 (released in 1987) had no GUI at all. Version 1.1 (released 1988) included Presentation Manager (PM), which looked a lot like the later Windows 3.0 UI. After the split with Microsoft, IBM developed the Workplace Shell (WPS) for version 2.0 (released in 1992), a quite radical, object-oriented approach to GUIs. Microsoft later imitated much of this in Windows 95.
BeOSX Window System
The PostScript-based NeWS (Network extensible Window System) was developed by Sun Microsystems. For several years SunOS included a window system combining NeWS and the X Window System. Although NeWS was considered technically elegant by some commentators, Sun eventually dropped the product. Unlike X, NeWS was always proprietary software.
The X Window System
The standard windowing system in the Unix world, developed in the early 1980s, is the X Window System, or X. X was developed at MIT as Project Athena. Its original purpose was to allow users of the newly emerging graphic terminals to access remote graphics workstations, without regard to the workstation’s operating system or the hardware. Due largely to the availability of the source code used to write X, it has become the standard layer for management of graphical and input/output devices and for the building of both local and remote graphical interfaces on virtually all systems, including UNIX, the BSD operating systems and the GNU/Linux distributions.
X allows a graphical terminal user to make use of remote resources on the network as if they were all located locally to the user by running a single module of software called the X server. The software running on the remote workstation is called the client application. X’s network transparency protocols allow the display and input portions of any application to be separated from the remainder of the application and ’served up’ to any of a large number of remote users.
In the early days of X Window development Sun Microsystems and AT&T attempted to push for a GUI standard called OpenLook in competition with Motif. OpenLook was a well-designed standard developed from scratch while MOTIF was a collective effort that fell into place. Many who worked on OpenLook at the time appreciate its design coherence. Motif prevailed the ’religious’ war and became the bases for CDE (Common Desktop Environment). Both X and Open Motif are available today as free software.
In the late 1990s, there was significant growth in the Unix world, especially among the free software community. New graphical desktop movements grew up around GNU/Linux and similar operating systems, based on the X. A new emphasis on providing an integrated and uniform interface to the user brought about new desktop environments, KDE and GNOME.
—-ADD—-
X Window System
The X Window System is a window system for computers with bitmap graphical displays created at MIT in the 1980s and now under the supervision of X.Org. Currently at version 11 release 6 (X11R6), it is more commonly called X11 or simply X. It is also often referred to as "X Windows", analogous to "Microsoft Windows", but this usage is incorrect and discouraged. A T-shirt seen at an X11 conference bore this sentiment: "It's a windowing system named 'X', not a system named 'X Windows'".
The X Window System was initially conceived in 1984, at the Massachusetts Institute of Technology as a joint project between their Laboratory for Computer Science and the Digital Equipment Corporation. The initial impetus for the X Window System was MIT's Project Athena, which sought to provide easy access to computing resources for all students. Because MIT could not buy all the workstations needed, nor was any single vendor willing to donate them, a platform-independent graphics system was required to link together the heterogenous systems. The first version of the X Window System to be widely deployed was Version 10 (X10). It was shortly thereafter superseded by Version 11 (X11) in 1987.
In 1988, a non-profit group called the (MIT) X Consortium was formed to direct future development of X standards in an atmosphere inclusive of many commercial and educational interests. The X Consortium produced several significant revisions to X11, concluding with Release 6 in 1994 (X11R6).
The X Consortium dissolved at the end of 1996, producing a final, small revision to X11R6 called X11R6.3. Ownership of X then passed to The Open Group, an outgrowth of the Open Software Foundation (OSF), who produced the popular Motif widget set for X. In early 1998, the Open Group released a further revision to X11R6, called X11R6.4 — a departure from the traditional licensing terms, however, prevented adoption of this version of the X Window System by many vendors, including the XFree86 Project, Inc. In late 1998, the Open Group relicensed X11R6.4 under terms identical with the traditional license.
In May 1999, stewardship of the X Window System passed from the Open Group to X.Org, a non-profit organization focused exclusively on maintenance and further development of the X Window System. X.Org has supervised the release of X11R6.5.1.
XFree86
XFree86 is a free and Open Source implementation of the X Window System which runs under Linux, FreeBSD, NetBSD, OpenBSD, Solaris, MacOS X, Windows NT and several other minor flavors of Unix. As of 1 October 2001, XFree86 supported the X11R6.5.1 spec, including the GLX and Render extensions.
The XFree86 project has recently been forked by Keith Packard, creating the XWin project; the new branch of the X server itself has been given the name Xouvert.
What is XFree86?
The XFree86 Project, Inc is a global volunteer organisation which produces XFree86®, a freely redistributable open-source implementation of the X Window System. XFree86 runs primarily on UNIX® and UNIX-like operating systems like Linux, all of the BSD variants, Sun Solaris both native 32 and 64 bit support, Solaris x86, Mac OS X (via Darwin), SGI's Irix as well as other platforms like OS/2 and Cygwin.
XFree86, provides a client/server interface between display hardware (the mouse, keyboard, and video displays) and the desktop environment while also providing both the windowing infrastructure and a standardized application interface (API).
XFree86 is platform-independent, network-transparent and extensible. In short, XFree86 is an open source X11-based desktop infrastructure with our goals and purpose detailed in our Mission Statement.
X.Org Foundation Background
On 22nd January 2004, the original members of X.Org and several industry participants announced the formation of The X.Org Foundation.
The X.Org Foundation will assume the role of being the worldwide consortium empowered with the stewardship and collaborative development of the X Window System technology and standards previously managed by X.Org.
The X.Org Foundation is a Delaware registered LLC, seeking to act as a scientific charity under the IRS 501(c)(3) code. Its mission is to maintain and enhance the existing X Window System code base, engineering appropriate enhancements that will be driven by current and future market requirements. The X.Org Foundation will periodically provide official X Window System update releases to the general public free of charge. The X.Org Foundation will govern the evolution of the X11R6 specifications, working with appropriate groups to revise and post updates to the standard as required.
The X.Org web-site will evolve into the home of the X.Org Foundation as the group and its operating procedures are defined.
关于 Design Mode 的一点认识
今天绝大部分时间用于解决了一个很小的问题,但是从中却了解到 Visual Studio.net 中 Design Mode 的一些实现方式。
从头开始,先来说说我遇到的这个问题:如何判但一个实例所对应的类是否实现了某一个接口?这其实也算不上什么问题,我起初也是知道的,就是和判断某个对象是否是某个类的实例一样,使用 is 关键字就可以了。但问题偏偏没有那么简单。
我的目的是想要实现这样一种功能,一个用户控件 (User Control) 被放到一个容器(之所以说是容器,因为它不一定只是 Form, 也有可能是 Tab page, Group box 等等)中,那么我需要这个用户控件去检查这个容器是否实现了我规定的一个接口,如果是才允许在这个容器中创建自己。
于是,问题接踵而来。首先,如何得到这个用户控件所在的容器,通过搜索 MSDN 得到两个属性,一个是 UserControl.Container, 另一个则是 UserControl.Parent. 前一个似乎很像,不过它返回的是一个 IContainer 接口的实例,无法直接使用;而后者相对较好,返回一个 Control (该类是所有 Windows 控件,包括 Form 的基类)类的实例。很自然,我就开始在这个属性上下文章。
假如我要指定实现的接口是 IMyInterface. 假如我使用 Form 作为该控件的容器,那么在 IDE 自动给我在默认窗体后面继承一个 System.Windows.Forms.Form 之外,还需要继承这个接口,这部分很简单但是当我使用 is 关键字进行如下判断时就出现了问题 this.Parent is IMyInterface (其中的 this 就是那个用户控件的实例),这个判断永远也通不过。后来我试图将其做一个强制类型转换,却得到了指定转换非法 (Spicified cast is invalid.) 的异常。原因就在于 this.Parent 返回一个 Control 类型,而该类型在 .net 类库中显然没有实现我的那个接口,自然转换非法是正常的。但如何解决呢?
马上就能想到的自然是自己重写一个 Control 类,让该类实现我的接口。其实完全可以重写一个 Form 类,来实现接口。然后再使得你创建的 Form 从你这个扩展了的 Form 去继承,再作如上的转换就不会有问题了。我也就是这样做的,不过稍微画蛇添足了一点:
public abstract class MyCustomForm : System.Windows.Forms.Form, IMyInterface {}
就是加了一个 abstract 关键字,以阻止用户从该类生成实例。这是就出现了下一个问题,从这个 MyCustomForm 继承的窗体无法在设计器中展现了!这个问题起初没有弄明白是怎么回事,于是我就先去掉 abstract 关键字,使得一切恢复正常。随后我在这个类中添加了一个返回 bool 类型的虚属性,并默认实现返回 false, 就像这样:
public virtual bool MyProperty {
get {
return false;
}
}
然后我在我真正的 Form 中 (起名为 MainForm)覆盖这个属性,并返回 true. 之后我在用户控件的 Load 事件方法中调用这个属性,然而奇怪的是当向窗体中添加这个用户控件的时候(注意此时仍处于 Design Mode),该属性一直都为 false, 既基类中的实现,也就是说似乎属性没有被覆盖。这时我就想到了一个关于何时使用基类中的方法,何时使用覆盖了的方法的问题。因为可以想得到,当你把 MainForm 转到 Control 之后(通过调用 UserControl.Parent 实现)原有 MainForm 中多余的成员是否会被丢掉,当再转换成 IMyInterface 的实例时是否将无法找到覆盖过的方法,以至于直接去调用积类中的方法。似乎这是理所当然的,但是我随后写了一个类似的小程序试验,结果发现并不是这样,原因也很简单,这些转换只是在引用上发生的,已有的实例中的内容并不会被销毁,那么出现这个问题就太诡异了。
仔细想呀想呀,联想到上面出现的那个 Design Mode 的问题,一切就都能揭示了。 简单的就一句话:Design Mode 在你操作时需要生成一个实例,然而该实例不是运行时的实例。具体来说,你在 Design Mode 中设计一个窗体,那么你会看见 IDE 自动为你创建了一个名叫 Form1 的类,并且继承自 System.Windows.Forms.Form, 同时生成一个可视化的窗体界面,这个界面是一个窗体的实例。但是这个实例不是 Form1 的实例,而是其基类 Form 的实例,原因就是,IDE 是在帮你设计这个 Form1, 显然此时这个 Form1 还不存在,存在的只是一堆代码而已。这样你就可以解释一切了,当我的基类被 abstract 的时候无法被实例化以后,自然设计器就没有办法为我创建这个类的实例使得我能进行可视化操作,但是你仍然可以将程序无误的跑起来。因为所谓的那个 Form1 并不是 abstract 的。也正因为如此,当我的 UserControl 在 Design Mode 时去调用 Interface 中的方法时,自然得到的就是基类中虚属性的实现,而在运行时,得到的就是覆盖了的属性的返回值,经过试验,答案却是是这样的。
另外,你可使用 UserControl.DesignMode 来判断其是处于设计时还是运行时。
使用 C# 实现图像的边缘检测
我本人对图像处理没什么兴趣,要不是这门课要交作业,我才懒得做这些东西。唉……不过程序写了,自然会有一点想法,发到 Blog 上,以备后用吧。但是,即便是写了程序,也仍然不知道作边缘检测的原理何在,只是模糊的知道大概是对图像灰度求梯度,梯度大的就是边缘了。但毕竟图像是离散化的,可以使用另外的方法求梯度,而不用像高数中那样拼命地算偏导数了。有很多学者提出了很多种不同性能的模板,只要按照模板作简单的四则运算就行了,当然这也是能用程序实现的关键。由于作为教学课程,所有的内容都是以简单的灰度图像来说明举例的,当然边缘检测也不例外,留作业写程序也是一样,所以马上就遇到的一个问题是如何将彩色图像转为灰度图像。在课程中,都是简单的认为灰度图像只有一个亮度,这自然是没错的,但是放到计算机里,灰度也是一种颜色,是颜色就要使用色彩模式(最常用的自然是 RGB 了),那么这种灰度到底应该是怎样的颜色编码呢?索性取向 Photoshop ,看一看各种灰度色调,终于有所发祥。其实也可以这么想,全黑是 #000000 ,全白是 #FFFFFF ,那么是不是只要 RGB 值都相等,这个颜色就是灰度色呢?试了一下,果然如此。这样就好办了,至少第一步知道了转换的目标是什么了。但马上就又有了一个问题,彩色图片的颜色这么多,那么如何知道哪种彩色颜色对应哪种灰度颜色呢?这一点我从 .net Framework 中找到了答案。其实我从一开始就想在 .net Framework 中寻找有没有直接将 RGB 转成灰度或者是 HIS 模式(因为 HIS 模式中的 I 就使亮度,自然就容易转成灰度了)的,是不是太奢望了,所以我也没抱太大的希望,但是在这过程中却发现 Color 中有关一个实例方法 GetBrightness() ,就是用来获得颜色亮度的,真是踏破铁鞋无觅处,得来全不费功夫。该方法返回一个 0~1 之间的浮点数,那么如果 RGB 每个各占一个字节的话,那么刚好可以用这个值去乘以 255 ,然后拼成一个 RGB ,这个颜色就是原始色彩所对应的灰色。程序代码如下:
//定义两个颜色变量,oColor为原始色彩,gColor为对应的灰度色彩
Color oColor,gColor;
//原始色彩的亮度
float brightness;
//灰度色彩用 RGB 来表示,由于 R=G=B 所以只用一个变量就可以了
int gRGB;
//遍历图像中的每个像素
for (int i = 0; i < oBmp.Width; i ++) {
for (int j = 0; j < oBmp.Height; j ++) {
//得到像素的原始色彩
oColor = oBmp.GetPixel(i,j);
//得到该色彩的亮度
brightness = oColor.GetBrightness();
//用该亮度计算灰度
gRGB = (int)(brightness * 255);
//组成灰度色彩
gColor = Color.FromArgb(gRGB,gRGB,gRGB);
//最后将该灰度色彩赋予该像素
gBmp.SetPixel(i,j,gColor);
}
}
其实还是很简单的。这之后就可以按照书中所说的模板游历的方法来进行边缘检测了。程序如下:
//template为模板,nThreshold是一个阈值,
//用来将模板游历的结果(也就是梯度)进行划分。
//大于阈值的和小于阈值的分别赋予两种颜色,白或黑来标志边界和背景
private void EdgeDectect(int[,] template,int nThreshold) {
//取出和模板等大的原图中的区域
int[,] gRGB = new int[3,3];
//模板值结果,梯度
int templateValue = 0;
//遍历灰度图中每个像素
for (int i = 1; i < gBmp.Width - 1; i ++) {
for (int j = 1; j < gBmp.Height - 1; j ++) {
//取得模板下区域的颜色,即灰度
gRGB[0,0] = gBmp.GetPixel(i-1,j-1).R;
gRGB[0,1] = gBmp.GetPixel(i-1,j).R;
gRGB[0,2] = gBmp.GetPixel(i-1,j+1).R;
gRGB[1,0] = gBmp.GetPixel(i,j-1).R;
gRGB[1,1] = gBmp.GetPixel(i,j).R;
gRGB[1,2] = gBmp.GetPixel(i,j+1).R;
gRGB[2,0] = gBmp.GetPixel(i+1,j-1).R;
gRGB[2,1] = gBmp.GetPixel(i+1,j).R;
gRGB[2,2] = gBmp.GetPixel(i+1,j+1).R;
//按模板计算
for (int m = 0; m < 3; m ++) {
for (int n = 0; n < 3; n ++) {
templateValue += template[m,n] * gRGB[m,n];
}
}
//将梯度之按阈值分类,并赋予不同的颜色
if (templateValue > nThreshold) {
eBmp.SetPixel(i,j,Color.FromArgb(255,255,255)); //白
} else {
eBmp.SetPixel(i,j,Color.FromArgb(0,0,0)); //黑
}
templateValue = 0;
}
}
}
.net Remoting 中的几个重要概念和实现方法
应用程序域 (Application domain)
一般的 Windows 应用程序都是以进程的方式在操作系统中运行,操作系统负责分配并管理程序所请求的资源。但是对于使用 .net 编写的托管程序而言,有一个特殊的进程被称为公共语言运行时 (CLR) ,该进程负责加载托管程序并运行。对于在 CLR 中运行的每一个托管程序而言,都有一个被称之为应用程序域的边界,每个托管程序都在自己的应用程序域中安全的运行。不同的应用程序域之间互不干扰。
上下文 (Application context)
将应用程序域进一步细分,就形成了上下文,上下文确保一套常用约束和使用语法负责管理其中的所有对象访问。每个应用程序域至少包含一个上下文,称为默认上 下文 (Default context) 。除非某个对象明确的要求一个专门的上下文,否则运行时 (Common language runtime) 将在默认上下文中创建那个对象。
.net Remoting 边界
对于应用程序而言应用程序域的边界是 .net Remoting 的边界。对应用程序域而言上下文的边界是 .net Remoting 边界,一个普通的对象无法穿越 .net Remoting 边界。
不可远程化对象和可远程化对象
一、不可远程化对象 (Non remotable object)
在默认情况下,没有经过任何特殊处理的对象都是不可远程化对象。不可远程化对象无法以任何方式(拷贝或引用)被跨应用程序域的对象所访问,当企图把对象引用传递到其他的应用程序域中时,会有异常产生。
二、可远程化对象 (emotable object) 如果一个类的实例可以穿越 .net Remoting 边界并可以在边界外被访问,则该对象就是可远程化的。在应用程序域外可远程化对象被访问的方式有两种:可以通过对象的完整副本来访问,还可以通过对象的引用(在 .net Remoting 中是以代理的模式来实现的)来访问。
.net Remoting 的服务器和客户端
.net Remoting 的服务器和客户端与以往的概念没有什么差别,但是在这里要强调的是 .net Remoting 的服器器和客户端显然是处于不同的应用程序域中,但是并不一定处于不同的计算机上。
按值列集 (Marshal by value) 和按引用列集 (Marshal by reference)
一、当运行时可以获得一个对象的完整副本的时候,则该对象就可以以所谓按值列集的方式被传递到其他的应用程序域中。实现按值列集的途径就是在声明类的时候添加 Serializable 特性 (Attribute) 或者实现 ISerializable 接口。例如:
[Serializable]
class Foo {
...
}
因此能够按值列集的对象也被称为可序列化的对象。客户端将获得该对象的完整副本。
二、当一个类直接或间接地从 MarshalByRefObject 类继承的时候,运行时就可以在客户端创建一个该对象的代理。例如:
class Foo : MarshalByRefObject {
...
}
上下文邦定 (Context bound)
当一个类型的实例只停留在具体的上下文内的时候,该类型就是上下文邦定的类型,在这个域内的其它上下文中的对象不能直接访问该对象。上下文邦定类型通过继承 System.ContextBoundObject 类来实现。
代理 (Proxy)
刚才提到,当对象以按引用列集的方式在应用程序域中传递的时候,运行时将在接收方创建一个该对象的代理。该代理可以想象为(通常也是这样实现的)一个封装了该对象所有或部分成员的接口,负责将接收方(客户端)的调用信息发送给发送方(服务器)。
通道 (Channel)
通道用于在跨应用程序域的远程对象间传递消息 (Message) 。服务器将选择侦听请求的通道,而客户端则选择希望与服务器进行通信的通道。运行时提供了两种内置的通道 Http 通道和 Tcp 通道。
using System.Runtime.Remoting; // .net Remoting 命名空间 using System.Runtime.Remoting.Channels; // .net Remoting 通道命名空间 using System.Runtime.Remoting.Channels.Http; // .net Remoting Http 通道命名空间 using System.Runtime.Remoting.Channels.Tcp; // .net Remoting Tcp 通道命名空间 . . . // ChannelServices 是一个工具类,里面封装了大量的与通道相关的静态方法 ChannelServices.RegisterChannel ( new HttpChannel() ); // 注册 Http 通道并使用默认端口 ChannelServices.RegisterChannel ( new TcpChannel(4242) ); // 注册 Tcp 通道并使用4242端口
激活 (Activation)
一、服务器端激活 (Server Activation)
服务器端激活方式是指对象的生存周期(何时生成与何时被垃圾回收)由服务器来决定。服务器端激活有两种方式:单件 (Singleton) 和单调用 (SingleCall) 。
二、客户端激活 (Client Activation)
客户端激活方式是指对象的生存周期由客户端来决定。客户端激活只有一种方式,称为 CAO (Client Activation Object) 。每一个客户端激活创建一个对象,该对象存在于如下两个事件之一到来之前:客户端失掉对对象的引用,对象租借过期。客户端激活模式可以存储每一个客户端的状态,并接受构造函数参数。可以使用如下的代码,在服务器端设置客户端激活的远程对象:
RemotingConfiguration.RegisterActivatedServiceType( typeof( SomeMBRType ) );
然后在客户端设置如下:
RemotingConfiguration.RegisterActivatedClientType( typeof( SomeMBRType ), "http://SomeURL" );
此处的 SomeURL 是指服务器端的地址或计算机名。
众所周知 (Well-known object) 的对象
服务器端激活的类型我们就称之为众所周知的。在使用众所周知的对象时,服务器要进行如下的设置:对象的类型,何时以及如何实例化对象,和一个客户端用来与该类型联系的名称(或叫终端 end point )。而同时客户端要设置连接到哪一个服务器,并在终端上获得众所周知的类型。使用 RemotingConfiguration.RegisterWellKnownServiceType 这个方法来注册一个众所周知的类型,该方法需要提供三个参数:待注册的类型,传达给客户端的终端名称和激活模式。例如:
using System.Runtime.Remoting; // .net Remoting 名名空间 . . . WellKnownServiceTypeEntry WKSTE = new WellKnownServiceTypeEntry( typeof( MyNameSpace.SomeMBRType ), "SomeURI", WellKnownObjectMode.SingleCall ); RemotingConfiguration.RegisterWellKnownServiceType(WKSTE);
其中先创建一个 WellKnownServiceTypeEntry 类型的对象,用于在 RegisterWellKnownServiceType 方法中传递参数。
typeof( MyNameSpace.SomeMBRType ) 这个参数待注册的远程对象的类型, SomeMBRType 是 MyNameSpace 命名空间下的一个类。
SomeURI 便是传达给客户端的终端名称。(它的用途在后面会介绍。)
WellKnownObjectMode.SingleCall 就是将该类型注册为单调用模式。
单件和单调用
一、单调用:服务器为每个客户端的方法调用生成一个单调用对象,每个对象服务且仅 服务一个请求。只有当方法调用到达的时候才按需求创建对象,并且对象的生存期直至调用结束。单调用模式适用于无需保存状态的应用程序,是解决负载平衡的最好选择。可以通过如下的方法在服务器端将可远程化类型配置为单调用模式:
// RemotingConfiguration 是一个工具类 RemotingConfiguration.RegisterWellKnownServiceType( typeof( SomeMBRType ), // 从 MasharlByRef 继承来的数据的类型信息 "SomeURI", // 发布该服务器端激活对象时使用的 URI WellKnownObjectMode.SingleCall ); // 设定为单调用模式
然后用如下的方法在客户端再配置一次:
RemotingConfiguration.RegisterWellKnownClientType( typeof( SomeMBRType ), // 要从服务器端得到的远程类型 "http://SomeWellKnownURL/SomeURI" ); // 众所周知的对象发布的 URL
二、单件:服务器在任何情况下都只创建该类型的一个实例,客户端的所有请求都由这 一个实例来处理,且该实例的生存期与服务器的生存期相同。单件模式适用于由状态的应用 程序,但是这种模式的对象只能保存非客户端的状态。同上面的代码,只要将 WellKnownObjectMode 设置为 Singleton 就可以了。
众所周知对象的 URL
服务器端激活的对象是在 URL 上发布的,该 URL 是被客户端众所周知的。众所周知对象的 URL 看上去如下:
ProtocolScheme://ComputerName:Port/ApplicationName/ObjectUri
其中 ProtocolScheme 代表 .net Remoting 通道所使用的协议,例如 Http 或 Tcp 等。
ComputerName 代表 .net Remoting 服务器的名称或地址。
Port 是注册通道时使用的端口。
ApplicationName 就是服务器端应用程序的名称。当使用 IIS 作为服务器端宿主的时候, ApplicationName 就变成了 IIS 的虚拟目录。
ObjectUri 就是在使用 RegisterWellKnownServiceType 时注册的 SomeURI 。 ObjectUri 必须以 .rem 或 .soap 结束,以区别是使用 Tcp 还是 Http 协议。
基于租借的生存期
客户端激活对象的生存期由与对象相关的租借来控制,租借有一个租借期, .net Remoting 基础设施在租借过期的时候放弃对象的引用,每一次方法调用可以更新租借,客户端可以使用代理更新租借,发起者也可以更新租期。
客户端激活对象的 URL
客户端激活对象不需要为每一个对象配备一个单独的 URL ,客户端激活对象的 URL 看上去如下:
ProtocolScheme://ComputerName:Port/ApplicationName
体验 Longhorn 4074
n 个 Longhorn 版本从微软泄漏,对我真是一个难以抗拒的诱惑。使得即便是我这 AMD 1200+ 256M SD 内存的机器也忍不住要来尝试一下。但 4074 并不是我装 Longhorn 的第一个版本。
想当初我装的第一个版本好像是 4015 ,有些记不清了。那次是在各大网站文章的蛊惑下,有了对新版本 Windows 靓丽界面的无穷向往,这才决心在我这烂机器里装上一回,果不其然,我的机器真是烂,几乎无法承受 4015 对资源的海量需求, CPU 占用率还好一些,内存几乎就是 100% ,硬盘也没有停转过,系统慢得要死,再加上右面的 Sidebar 的捣乱,于是第一次尝试暂告失败。但总也有了些收获,首先是目睹了传说中 Longhorn 的界面,除了右面的 Sidebar ,其余的东西还是挺令我失望的,真有些和所谓的“下一代”相差甚远,但转念一想,毕竟是个开发中的版本,如果这时的性能就弄得和两三年后的一样,那还有机器能跑得起来吗:)其次就是看到了IIS的新版本 7.0 ,虽不知它比 6.0 能多了哪些东西,但也是个主版本号的提升呀,值得兴奋一下;第三,也是我个人比较关心的,就是 .net Framework 2.0 ,微软虽然这样说,但从 .net Framework 的目录中看到的却是 1.2.xxxx 的编译版本,显然与 2.0 还相差甚远,但这一点在 4074 就完全不一样了。
就这样我又开始等待 Longhorn 的下一个版本,等到的就是哪个所谓的轻量级版本,毫不隐瞒的说,这是我到目前见到的 Longhorn 的最烂的版本,也许对于我的需求来说是这样的。但我个人还是很佩服这个修改安装成程序的家伙的,将很多东西都从安装中去掉,并且也给出了如何启用这些功能的方法,但遗憾的是,我按照他说的做了,得到的结果却是中途安装出错,无法继续。但通过这一出错我到验证了一个疑问, Longhorn 确实有些代码是用 .net 写的,因为从它给出的错误日志中可以看到,其中用了大量的异常、抛出和捕获之类的词。为什么我说这个版本烂?其实很简单,不能否认,这个版本对资源的需求确实少了许多,像我这样的机器可以很流畅的跑起来,但这只是对一个普通用户而言的,他能用自己比较古老的机器来体验新一代的操作系统的华丽外观,感觉多好。但毕竟我是学计算机的,搞编程和开发才是我希望的。而且加之在等待的这段时间里,有越来越多的关于 Longhorn 主体的技术文章出来,我就是从中知道了什么所谓的 WinFS, Indigo, Avalon 和 XAML 等等,很期待试一试,遗憾这个轻量级版本无法支持,所以对它的第一印象就这样被打上了一个烂的标记。不过我还是推荐那些只想尝尝鲜,而又没有开发需求的朋友来装这个版本。顺便提一下,这个版本的安装程序的界面与 4015 和 4074 都不一样,比较友好,很像 XP ,除了颜色基调是深色的之外。不知是不是破解了的缘故。
下面就该提到重头戏 4074 了,无疑这是到目前我见到的最好的版本,除了安装界面有些“简朴”之外(如果微软在发布 Longhorn 之后也用这个安装界面的话,肯定会吓倒不少用户),其余都可以说能得个不错的分数。
第一、未经过修改,而且系统资源占用较少,像我这样的机器,跑起来不算很慢(加上 Sidebar 也不慢)。除了在启动时有些慢之外,其余的时候拿它工作上网是不成问题的。(这里还有一点需要补充,就是那个轻量级的版本不能上网,不知是怎么回事?)
第二、除了依旧是 IIS 7.0 之外,这回可是真正的 .net Framework 2.0 了,编译版本号为 2.0.31113 。而其在 .net 的目录里面里面很惊奇的发现除了以往常见的那个 Framework 的目录之外,还可以看到像 Avalon 这样的目录。显然在这个版本的 .net Framework 里面已经可以支持 Avalon 这样的命名空间了,也就是可以使用 XAML 来进行编程了。这个我试过了,挺爽的。
第三、向下兼容性非常好,一些在以往的 Windows 里可以装的软件,像虚拟光驱这样的软件都可以安装并能正常使用(虽然安装的时候提示出现错误),而且某些常用的编程几口也没有改变。这也许是个优点,但更像是一个不足,因为据我了解,微软当初在提到Longhorn的时候说其与以前的系统完全不兼容,我不知道现在这样的是因为开发没有完成,还是和用户妥协。
第四、微软提供了一个新的下载管理器,可以实现多线程下载,估计到那时,没有特殊功能的下载软件也该退休了。
我估计优点有以上记这些也就差不多了,下面就该说说缺点与不足了。
第一、也是最不能令我忍受的竟然无法实现先新建文件夹的功能。你用右键点击桌面,选择新建,看到了吗,里面没有新建文件夹;而且在资源管理器的界面上面放 着赫然写着 Make a new folder 的大按钮,但点了这后啥用也没有。真不知道微软这帮大哥们成天都在想着着哈?
第二、 Properties 用于文件夹时无法给出文件夹的大小。
第三、安全模式无法使用,当你进入安全模式的时候会不断地弹出那个告诉你现在是工作在安全模式下的那个对话框,但就是进不去。
第四、 OUtlook Express 在运行时会出错,自带两个版本的 Messenger 6.0 和 6.1 ,不知是为什么,而且那个 6.0 的版本几乎用不了。所以干脆还是把他们都卸载算了。
第五、该版本的 Longhorn 安装需要 3 个多G的空间,估计它是将整个的 I386 目录都装了进去,因为在以后添加 Windows 组建的时候,就不再需要安装盘了。而且, Longhorn 也不能再使用像以前那样先执行 smartdrv 再在 I386 目录中执行winnt命令来安装系统了。
第六、不算是问题,只能是不足,那就是 4074 这个版本还不支持 WinFS 。我在 MSDN 里面的一篇文章中看到,由于 Longhorn 的开发时间紧迫,所以原定被全面采用的 WinFS 文件系统现在被计划为只应用于 Documents and Settings 文件夹,其余还保持 NTFS 。
对 Longhorn 4074 的初体验到这就差不多了。其实里面还是有很多其他问题的,不过大家只要用过了,自然就会碰到,我在这里就不说了。关于 Longhron 非常独特的编程环境我还没有仔细使用,待以后有机会再写另一篇 Blog 吧。
到发稿时止,我正在 Longhorn 下装 Whidbey。
哈哈!挺爽。对了, 4074 已经有破解了。
设计模式 — Builder
上下文:一个产品有 n 个零件,通过构建产品的不同部分来生产不同的产品。
解决方法:将一个产品的不同部件交由某个构建者的不同方法来实现,然后导演通过调用不同的方法,构建出不同的产品。
using System;
namespace Builder {
/// <summary>
/// 产品,其中包括两个部件
/// </summary>
public class Product {
string part1 = string.Empty;
string part2 = string.Empty;
public string Part1 {
get { return part1; }
set { part1 = value; }
}
public string Part2 {
get { return part2; }
set { part2 = value; }
}
}
/// <summary>
/// 构建者的接口标准
/// </summary>
public interface IBuilder {
void BuildPart1();
void BuildPart2();
Product RetrieveProduct { get; }
}
/// <summary>
/// 从接口派生出具体的构建者
/// </summary>
public class ConcreteBuilder:IBuilder {
Product myProduct = new Product();
#region IBuilder 成员
public void BuildPart1() {
// TODO: 添加 ConcreteBuilder.BuildPart1 实现
myProduct.Part1 = "Part1 has been built!";
}
public void BuildPart2() {
// TODO: 添加 ConcreteBuilder.BuildPart2 实现
myProduct.Part2 = "Part2 has been built!";
}
public Product RetrieveProduct {
get {
// TODO: 添加 ConcreteBuilder.RetrieveProduct getter 实现
return myProduct;
}
}
#endregion
}
/// <summary>
/// 导演通过调用具体构建者的不同构建方法,构建不同的部件,进而行成不同的产品
/// 该导演生产了这样的三种产品
/// 1、具有零件 1 和 2 的产品
/// 2、只具有零件 1 的产品
/// 3、只具有零件 2 的产品
/// </summary>
public class Director {
Product product1, product2, product3;
public Product Product1 {
get { return product1; }
}
public Product Product2 {
get { return product2; }
}
public Product Product3 {
get { return product3; }
}
public Director() { }
public void Construct() {
ConcreteBuilder myCB1 = new ConcreteBuilder();
myCB1.BuildPart1();
myCB1.BuildPart2();
product1 = myCB1.RetrieveProduct;
ConcreteBuilder myCB2 = new ConcreteBuilder();
myCB2.BuildPart1();
product2 = myCB2.RetrieveProduct;
ConcreteBuilder myCB3 = new ConcreteBuilder();
myCB3.BuildPart2();
product3 = myCB3.RetrieveProduct;
}
}
/// <summary>
/// 测试 Builder 模式
/// </summary>
class TestBuilder {
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main(string[] args) {
Director myDirector = new Director();
myDirector.Construct();
Console.WriteLine(myDirector.Product1.Part1);
Console.WriteLine(myDirector.Product1.Part2);
Console.WriteLine(myDirector.Product2.Part1);
Console.WriteLine(myDirector.Product2.Part2);
Console.WriteLine(myDirector.Product3.Part1);
Console.WriteLine(myDirector.Product3.Part2);
Console.Read();
}
}
}
You are currently browsing the archives for the 计算机科学与技术 category.