📄 《_net编程先锋c#》第五章 类_c#语言_网络教程.htm
字号:
只存在一个差别,那就是:你几乎可以任意定义大括弧中的参数。限制为,必须至少规定一个参数,允许ref 和out
修饰符。<BR>this关键字确保一个解释。索引没有用户定义的名字,this
表示默认接口的索引。如果类实现了多个接口,你可以增加更多个由InterfaceName.this说明的索引。
<BR><BR>为了演示一个索引的使用,我创建了一个小型的类,它能够解析一个主机名为IP地址——或一个IP地址列表(以http://www.microsoft.com为例
)。这个列表通过索引可以访问,你可以看一下清单 <BR><BR>5.10 的具体实现。 <BR><BR>清单 5.10
通过一个索引获取一个IP地址 <BR><BR>1: using System;<BR>2: using
System.Net;<BR>3: <BR>4: class ResolveDNS<BR>5: {<BR>6: IPAddress[]
m_arrIPs;<BR>7: <BR>8: public void Resolve(string strHost)<BR>9:
{<BR>10: IPHostEntry iphe = DNS.GetHostByName(strHost);<BR>11:
m_arrIPs = iphe.AddressList;<BR>12: }<BR>13: <BR>14: public
IPAddress this[int nIndex]<BR>15: {<BR>16: get<BR>17: {<BR>18:
return m_arrIPs[nIndex];<BR>19: }<BR>20: }<BR>21: <BR>22: public int
Count<BR>23: {<BR>24: get { return m_arrIPs.Length; }<BR>25:
}<BR>26: }<BR>27: <BR>28: class DNSResolverApp<BR>29: {<BR>30:
public static void Main()<BR>31: {<BR>32: ResolveDNS myDNSResolver =
new ResolveDNS();<BR>33:
myDNSResolver.Resolve("http://www.microsoft.com");<BR>34: <BR>35:
int nCount = myDNSResolver.Count;<BR>36: Console.WriteLine("Found
{0} IP's for hostname", nCount);<BR>37: for (int i=0; i < nCount;
i++)<BR>38: Console.WriteLine(myDNSResolver[i]);<BR>39: } <BR>40: }
<BR><BR>为了解析主机名,我用到了DNS类,它是System .Net
名字空间的一部分。但是,由于这个名字空间并不包含在核心库中,所以必须在编译命令行中引用该库:<BR>csc
/r:System.Net.dll /out:resolver.exe dnsresolve.cs<BR>解析代码是向前解析的。在该
Resolve方法中,代码调用DNS类的静态方法GetHostByName,它返回一个IPHostEntry对象。结果,该对象包含有我要找的数组——AddressList数组。在退出Resolve
方法之前,在局部的对象实例成员m_arrIPs中,存储了一个AddressList array的拷贝(类型IPAddress
的对象存储在其中)。<BR>具有现在生成的数组
,通过使用在类ResolveDNS中求得的索引,应用程序代码就可以在第37至38行列举出IP地址。(在第6章
"控制语句",有更多有关语句的信息。)
因为没有办法更改IP地址,所以仅给索引使用了get存取标志。为了简单其见,我忽略了数组的边界溢出检查。<BR><BR>5.4
事件<BR>当你写一个类时,有时有必要让类的客户知道一些已经发生的事件。如果你是一个具有多年编程经验的程序员,似乎有很多的解决办法,包括用于回调的函数指针和用于ActiveX控件的事件接收(event
sinks)。现在你将要学到另外一种把客户代码关联到类通知的办法——使用事件。<BR>事件既可以被声明为类域成员(成员变量),也可以被声明为属性。两者的共性为,事件的类型必定是代表元,而函数指针原形和C#的代表元具有相同的含义。<BR>每一个事件都可以被0或更多的客户占用,且客户可以随时关联或取消事件。你可以以静态或者以实例方法定义代表元,而后者很受C++程序员的欢迎。<BR>既然我已经提到了事件的所有功能及相应的代表元,请看清单5.11中的例子。它生动地体现了该理论。
<BR><BR>清单5.11 在类中实现事件处理<BR>1: using System;<BR>2: <BR>3: //
向前声明<BR>4: public delegate void EventHandler(string strText);<BR>5:
<BR>6: class EventSource<BR>7: {<BR>8: public event EventHandler
TextOut;<BR>9: <BR>10: public void TriggerEvent()<BR>11: {<BR>12: if
(null != TextOut) TextOut("Event triggered");<BR>13: }<BR>14:
}<BR>15: <BR>16: class TestApp<BR>17: {<BR>18: public static void
Main()<BR>19: {<BR>20: EventSource evsrc = new EventSource();<BR>21:
<BR>22: evsrc.TextOut += new EventHandler(CatchEvent);<BR>23:
evsrc.TriggerEvent();<BR>24: <BR>25: evsrc.TextOut -= new
EventHandler(CatchEvent);<BR>26: evsrc.TriggerEvent();<BR>27:
<BR>28: TestApp theApp = new TestApp();<BR>29: evsrc.TextOut += new
EventHandler(theApp.InstanceCatch);<BR>30:
evsrc.TriggerEvent();<BR>31: }<BR>32: <BR>33: public static void
CatchEvent(string strText)<BR>34: {<BR>35:
Console.WriteLine(strText);<BR>36: }<BR>37: <BR>38: public void
InstanceCatch(string strText)<BR>39: {<BR>40:
Console.WriteLine("Instance " + strText);<BR>41: }<BR>42: }
<BR><BR>第4行声明了代表元(事件方法原形),它用来给第8行中的EventSource类声明TextOut事件域成员。你可以观察到代表元作为一种新的类型声明,当声明事件时可以使用代表元。<BR>该类仅有一个方法,它允许我们触发事件。请注意,你必须进行事件域成员不为null的检测,因为可能会出现没有客户对事件感兴趣这种情况。<BR>TestApp类包含了Main
方法,也包含了另外两个方法,它们都具备事件所必需的信号。其中一个方法是静态的,而另一个是实例方法。<BR>EventSource
被实例化,而静态方法CatchEvent被预关联上了 TextOut事件:<BR>evsrc.TextOut += new
EventHandler(CatchEvent);<BR>从现在起,当事件被触发时,该方法被调用。如果你对事件不再感兴趣,简单地取消关联:<BR>evsrc.TextOut
-= new
EventHandler(CatchEvent);<BR>注意,你不能随意取消关联的处理函数——在类代码中仅创建了这些处理函数。为了证明事件处理函数也和实例方法一起工作,余下的代码建立了TestApp
的实例,并钩住事件处理方法。<BR>事件在哪方面对你特别有用?你将经常在ASP+中或使用到WFC (<A class=wordstyle
href="http://www.zhaoxi.net/" target=_blank>Windows</A> Foundation
Classes)时,涉及到事件和代表元。 <BR><BR>5.5
应用修饰符<BR>在这一章的学习过程中,你已经见过了象public、virtual等修饰符。欲以一种易于理解的方法概括它们,我把它们划分为三节:
<BR><BR>。类修饰符<BR>。成员修饰符 <BR>。存取修饰符 <BR><BR>5.5.1
类修饰符<BR>到目前为止,我还没有涉及到类修饰符,而只涉及到了应用于类的存取修饰符。但是,有两个修饰符你可以用于类:<BR>abstract——关于抽象类的重要一点就是它不能被实例化。只有不是抽象的派生类才能被实例化。派生类必须实现抽象基类的所有抽象成员。你不能给抽象类使用sealed
修饰符。<BR>sealed——密封
类不能被继承。使用该修饰符防止意外的继承,在.NET框架中的类用到这个修饰符。<BR>要见到两个修饰符的运用,看看清单5.12
,它创建了一个基于一个抽象类的密封类(肯定是一个十分极端的例子)。 <BR><BR>清单 5.12 抽象类和密封类 <BR><BR>1:
using System;<BR>2: <BR>3: abstract class AbstractClass<BR>4:
{<BR>5: abstract public void MyMethod();<BR>6: }<BR>7: <BR>8: sealed
class DerivedClass:AbstractClass<BR>9: {<BR>10: public override void
MyMethod()<BR>11: {<BR>12: Console.WriteLine("sealed class");<BR>13:
}<BR>14: }<BR>15: <BR>16: public class TestApp<BR>17: {<BR>18:
public static void Main()<BR>19: {<BR>20: DerivedClass dc = new
DerivedClass();<BR>21: dc.MyMethod();<BR>22: }<BR>23: }
<BR><BR>5.5.2
成员修饰符<BR>与有用的成员修饰符的数量相比,类修饰符的数量很少。我已经提到了一些,这本书即将出现的例子描述了其它的成员修饰符。<BR>以下是有用的成员修饰符:<BR>abstract——说明一个方法或存取标志不能含有一个实现。它们都是隐式虚拟,且在继承类中,你必须提供
override关键字。<BR>const——这个修饰符应用于域成员或局部变量。在编译时常量表达式被求值,所以,它不能包含变量的引用。<BR>event
——定义一个域成员或属性作为类型事件。用于捆绑客户代码到类的事件。<BR>extern——告诉编译器方法实际上由外部实现。第10章
“和非受管代码互相操作”
将全面地涉及到外部代码。<BR>override——用于改写任何基类中被定义为virtual的方法和存取标志。要改写的名字和基类的方法必须一致。<BR>readonly——一个使用
readonly修饰符的域成员只能在它的声明或者在包含它的类的构造函数中被更改。
<BR><BR>static——被声明为static的成员属于类,而不属于类的实例。你可以用static
于域成员、方法、属性、操作符甚至构造函数。<BR>virtual——说明方法或存取标志可以被继承类改写。 <BR><BR>5.5.3
存取修饰符<BR>存取修饰符定义了某些代码对类成员(如方法和属性)的存取等级。你必须给每个成员加上所希望的存取修饰符,否则,默认的存取类型是隐含的。<BR>你可以应用4个
存取修饰符之一:<BR>public——任何地方都可以访问该成员,这是具有最少限制的存取修饰符。<BR>protected——在类及所有的派生类中可以访问该成员,不允许外部访问。<BR>private——仅仅在同一个类的内部才能访问该成员。甚至派生类都不能访问它。<BR>internal——允许相同组件(应用程序或库)的所有代码访问。在.NET组件级别,你可以把它视为public,而在外部则为private。<BR>为了演示存取修饰符的用法,我稍微修改了Triangle例子,使它包含了新增的域成员和一个新的派生类(见清单
5.13)。 <BR><BR>清单 5.13 在类中使用存取修饰符 <BR><BR>1: using System;<BR>2:
<BR>3: internal class Triangle<BR>4: {<BR>5: protected int m_a, m_b,
m_c;<BR>6: public Triangle(int a, int b, int c)<BR>7: {<BR>8: m_a =
a;<BR>9: m_b = b;<BR>10: m_c = c;<BR>11: }<BR>12: <BR>13: public
virtual double Area()<BR>14: {<BR>15: // Heronian formula<BR>16:
double s = (m_a + m_b + m_c) / 2.0;<BR>17: double dArea =
Math.Sqrt(s*(s-m_a)*(s-m_b)*(s-m_c));<BR>18: return dArea;<BR>19:
}<BR>20: }<BR>21: <BR>22: internal class Prism:Triangle<BR>23:
{<BR>24: private int m_h;<BR>25: public Prism(int a, int b, int c,
int h):base(a,b,c)<BR>26: {<BR>27: m_h = h;<BR>28: }<BR>29: <BR>30:
public override double Area()<BR>31: {<BR>32: double dArea =
base.Area() * 2.0;<BR>33: dArea += m_a*m_h + m_b*m_h +
m_c*m_h;<BR>34: return dArea;<BR>35: }<BR>36: }<BR>37: <BR>38: class
PrismApp<BR>39: {<BR>40: public static void Main()<BR>41: {<BR>42:
Prism prism = new Prism(2,5,6,1);<BR>43:
Console.WriteLine(prism.Area());<BR>44: }<BR>45: } <BR><BR>Triangle
类和 Prism 类现在被标为 internal。这意味着它们只能在当前组件中被访问。
<BR><BR>请记住“.NET组件”这个术语指的是包装( packaging,),而不是你可能在COM+中用到的组件。
<BR><BR>Triangle 类有三个
protected成员,它们在构造函数中被初始化,并用于面积计算的方法中。由于这些成员是protected
成员,所以我可以在派生类Prism中访问它们,在那里执行不同的面积计算。
<BR><BR>Prism自己新增了一个成员m_h,它是私有的——甚至派生类也不能访问它。<BR>花些时间为每个类成员甚至每个类计划一种保护层次,通常是个好主意。当需要引入修改时,全面的计划最终会帮助你,因为没有程序员会愿意使用“没有文档”的类功能。<BR>5.6
小结<BR>这章显示了类的各种要素,它是运行实例(对象)的模板。在一个对象的生命期,首先被执行的代码是个构造函数。构造函数用来初始化变量,这些变量后来在方法中用于计算结果。<BR>方法允许你传递值、引用给变量,或者只传送一个输出值。方法可以被改写以实现新的功能,或者你可以屏蔽基类成员,如果它实现了一个具有和派生类成员相同名字的方法。<BR>命名属性可以被当作域成员(成员变量)或属性存取标志实现。后者是get和set存取标志,忽略一个或另外一个,你可以创建仅写或仅读属性。存取标志非常适合于确认赋给属性的值。<BR>C#类的另外一个功能是索引,它使象数组语法一样访问类中值成为可能。还有,如果当类中的某些事情发生时,你想客户得到通知,要让它们与事件关联。<BR>当垃圾收集器调用析构函数时,对象的生命就结束了。由于你不能准确地预测这种情况什么时候会发生,所以应该创建一个方法以释放这些宝贵的资源,当你停止使用它们时
<BR></TD></TR>
<TR>
<TD vAlign=top align=justify>
<DIV class=adsense id=ad003>
<P> </P></DIV></TD></TR>
<TR>
<TD colSpan=3 height=12>
<LI>上一篇文章: <A class=LinkPrevArticle
title="文章标题:《.net编程先锋C#》第六章 控制语句 作 者:佚名 更新时间:2006-5-8 14:35:32"
href="http://www.qostudy.org/pr/Article/aspnet/c/200605/16914.html">《.net编程先锋C#》第六章 控制语句</A><BR>
<LI>下一篇文章: <A class=LinkNextArticle
title="文章标题:《.net编程先锋C#》第四章 C#类型 作 者:佚名 更新时间:2006-5-8 14:35:32"
href="http://www.qostudy.org/pr/Article/aspnet/c/200605/16916.html">《.net编程先锋C#》第四章 C#类型</A></LI></TD></TR></TBODY></TABLE></DIV></TD></TR>
<TR>
<TD width="100%">
<P align=right> </P></TD></TR></TBODY></TABLE>
<SCRIPT src="《_net编程先锋C#》第五章 类_C#语言_网络教程.files/count.htm"
type=text/javascript></SCRIPT>
<TABLE style="BORDER-COLLAPSE: collapse" height=55 cellPadding=0 width=760
border=0>
<TBODY>
<TR>
<TD vAlign=bottom height=26>
<P align=left>Copyright Qostudy© 2002-2006 All Rights Reserved
网络教程</P></TD></TR>
<TR>
<TD
style="BORDER-TOP: #a43232 1px solid; BORDER-LEFT-WIDTH: 1px; BORDER-BOTTOM-WIDTH: 1px; BORDER-RIGHT-WIDTH: 1px">
<P align=left>电信备案许可证 京ICP备02003422号 <A
href="http://www.qostudy.org/pr/sitemap/Article1.htm">SiteMap</A>
<SCRIPT language=javascript
src="《_net编程先锋C#》第五章 类_C#语言_网络教程.files/366882.js"
type=text/javascript></SCRIPT>
<NOSCRIPT><A href="http://www.51.la/?366882" target=_blank><IMG
style="BORDER-RIGHT: medium none; BORDER-TOP: medium none; BORDER-LEFT: medium none; BORDER-BOTTOM: medium none"
alt=我要啦免费统计
src="《_net编程先锋C#》第五章 类_C#语言_网络教程.files/s.htm"></A></NOSCRIPT></P></TD></TR></TBODY></TABLE><!-- Powered by: PowerEasy 2005 --></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -