ASP.NET编程:[你必需晓得的.NET]第九回:咀嚼范例――值范例与援用范例(中)-划定规矩无边仓酷云 ...
对于new隐藏成员的作用,往往是出于使用了一个第三方类库,而你又无法获得这个类库的源代码,当你继承这个类库的某个类时,你需要重新实现其中的一个方法,而又需要与父类中的函数使用同样的函数,这是就需要在自定义的子类中把那个同名函数(或成员)加上new标记,从而隐藏父类中同名的成员。系列文章目次索引:《你必需晓得的.NET》接上回[第八回:咀嚼范例---值范例与援用范例(上)-内存有理]的切磋,持续我们存眷值范例和援用范例的话题。
本文将先容以下内容:
[*]范例的基础观点
[*]值范例深切
[*]援用范例深切
[*]值范例与援用范例的对照及使用
1.弁言
上回[第八回:咀嚼范例---值范例与援用范例(上)-内存有理]的公布,遭到人人的很多存眷,我们从内存的角度懂得了值范例和援用范例的以是然,留下的义务固然是怎样使用范例的分歧特性在体系计划、功能优化等方面发扬其感化。因而,本回是对上回无力的增补,同时应伴侣的但愿,我们全力从内存调试的角度来着眼一些计划的剖析,如许就有助于对这一主题举行透辟和周全的了解,固然这也是下一回的重点。
从内存角度来会商值范例和援用范例是有理有据的,而从划定规矩的角度来懂得值范例和援用范例是一望无际的。本文旨在从上文照应的角度,来把这个主题完全的举一反三,无边无迹的使用,仍是来自反复不定的理论,因而对使用我只能说以一个角度来阐释概念,可是一定不成才能责备局。因而,我们从以下几个角度来完成对值范例与援用范例使用范畴的会商。
2.通用划定规矩与对照
通用有划定规矩:
[*]string范例是个特别的援用范例,它承继自System.Object一定是个援用范例,可是在使用体现上又凸现出值范例的特性,那末事实是甚么缘故原由呢?比方有以下的一段实行:
<br>
复杂的说是因为string的immutable特征,因而每次对string的改动城市在托管堆中发生一个新的string变量,上述string作为参数传送时,实践上实行了s=s操纵,在托管堆中会发生一个新的空间,并实行数据拷贝,以是才有了相似于按值传送的了局。可是依据我们的内存剖析可知,string在实质上仍是一个援用范例,在参数传送时产生的仍是按址传送,不外因为其特别的恒定特征,在函数外部新建了一个string对象并完成初始化,可是函数内部取不到这个变更的了局,因而对表面现的特征就相似于按值传送。至于string范例的特别性注释,我保举Artech的高文《深切了解string和怎样高效地利用string》。
别的,string范例重载了==操纵符,在范例对照是对照的是实践的字符串,而不是援用地点,因而有以下的实行了局:
stringaString="123";
stringbString="123";
Console.WriteLine((aString==bString));//显现为true,等价于aString.Equals(bString);
stringcString=bString;
cString="456";
Console.WriteLine((bString==cString));//显现为false,等价于bString.Equals(cString);
[*]一般可使用Type.IsValueType来判别一个变量的范例是不是为值范例,典范的操纵为:
publicstructMyStructTester
{}
publicclassisValueType_Test
{
publicstaticvoidMain()
{
MyStructTesteraStruct=newMyStructTester();
Typetype=aStruct.GetType();
if(type.IsValueType)
{
Console.WriteLine("{0}belongstovaluetype.",aStruct.ToString());
}
}
}
[*].NET中以操纵符ref和out来标识值范例按援用范例体例传送,个中区分是:ref在参数传送之前必需初始化;而out则在传送前不用初始化,且在传送时必需显式赋值。
[*]值范例与援用范例之间的转换历程称为装箱与拆箱,这值得我们以专门的篇幅来会商,因而留待后文具体会商这一主题。
[*]sizeof()运算符用于猎取值范例的巨细,可是不合用于援用范例。
[*]值范例利用new操纵符完成初始化,比方:MyStructaTest=newMyStruct();而纯真的界说没有完成初始化举措,此时对成员的援用将不克不及经由过程编译,比方:
MyStructaTest;
Console.WriteLine(aTest.X);
[*]援用范例在功能上欠于值范例次要是由于以下几个方面:援用范例变量要分派于托管堆上;内存开释则由GC完成,形成必定的CG堆压力;同时必需完成对其附加成员的内存分派历程;和对象会见成绩。因而,.NET体系不克不及由地道的援用范例来统治,功能和空间加倍优胜和易于办理的值范例有其一席之地,如许我们就不会由于一个复杂的byte范例而举行庞大的内存分派和开释事情。Richter就称值范例为“轻量级”范例,几乎恰到好处,处置数据较小的情形时,应当优先思索值范例。
[*]值范例都承继自System.ValueType,而System.ValueType又承继自System.Object,其次要区分是ValueType重写了Equals办法,完成对值范例依照实例值对照而不是援用地点来对照,详细为:
chara="c";
charb="c";
Console.WriteLine((a.Equals(b)));//会前往true;
[*]基元范例,是指编译器间接撑持的范例,其观点实际上是针对详细编程言语而言的,比方C#大概VB.NET,一般对使用.NETFramework界说的内置值范例。这是观点上的界线,不成搅浑。比方:int对应于System.Int32,float对应于System.Single。
对照出真知:
[*]值范例承继自ValueType(注重:而System.ValueType又承继自System.Object);而援用范例承继自System.Object。
[*]值范例变量包括实在例数据,每一个变量保留了其自己的数据拷贝(正本),因而在默许情形下,值范例的参数传送不会影响参数自己;而援用范例变量保留了其数据的援用地点,因而以援用体例举行参数传送时会影响到参数自己,由于两个变量会援用了内存中的统一块地点。
[*]值范例有两种暗示:装箱与拆箱;援用范例只要装箱一种情势。我会鄙人节以专门的篇幅来深切会商这个话题。
[*]典范的值范例为:struct,enum和大批的内置值范例;而能称为类的都能够说是援用范例。struct和class次要的区分能够拜见我的拙作《第四回:后发先至:class和struct》来具体懂得,也是对值范例和援用范例在使用方面的无力增补。
[*]值范例的内存不由GC(渣滓接纳,GabageCollection)把持,感化域停止时,值范例会自行开释,削减了托管堆的压力,因而具有功能上的上风。比方,一般struct比class更高效;而援用范例的内存接纳,由GC来完成,微软乃至倡议用户最好不要自行开释内存。
[*]值范例是密封的(sealed),因而值范例不克不及作为其他任何范例的基类,可是能够单承继大概多承继接口;而援用范例一样平常都有承继性。
[*]值范例不具有多态性;而援用范例有多态性。
[*]值范例变量不成为null值,值范例城市自行初始化为0值;而援用范例变量默许情形下,创立为null值,暗示没有指向任何托管堆的援用地点。对值为null的援用范例的任何操纵,城市抛出NullReferenceException非常。
[*]值范例有两种形态:装箱和未装箱,运转库供应了一切值范例的已装箱情势;而援用范例一般只要一种情势:装箱。
3.有的放矢-使用场所与注重事项
如今,在内存机制懂得和通用划定规矩熟习的基本上,我们就能够很好的总结出值范例和援用范例在体系计划时,怎样作出选择?固然我们的重点是告知你,怎样往选择利用值范例,由于援用范例才是.NET的主体,不用花太多的照顾就能够博得市场。
3.1值范例的使用场所
[*]MSDN中倡议以范例的巨细作为选择值范例大概援用范例的决意性要素。数据较小的场所,最好思索以值范例来完成能够改良体系功能;
[*]布局复杂,不用多态的情形下,值范例是较好的选择;
[*]范例的性子不体现出举动时,不用以类来完成,那末用以存储数据为次要目标的情形下,值范例是优先的选择;
[*]参数传送时,值范例默许情形下传送的是实例数据,而不是内存地点,因而数据传送情形下的选择,取决于函数外部的完成逻辑。值范例能够有高效的内存撑持,而且在不表露外部布局的情形下前往实例数据的正本,从平安性上能够思索值范例,可是过量的值传送也会毁伤功能的优化,应得当选择;
[*]值范例没有承继性,假如范例的选择没有子类承继的需要,优先思索值范例;
[*]在大概会引发装箱与拆箱操纵的汇合大概行列中,值范例不是很好的选择,由于会引发对值范例的装箱操纵,招致分外内存的分派,比方在Hashtable。关于这点我将在后续的主题中重点会商。
3.2援用范例的使用场所
[*]能够复杂的说,援用范例是.NET天下的全值杀手,我们能够说.NET天下就是由类组成的,类是面向对象的基础观点,也是程序框架的基础要素,因而天真的数据封装特征使得援用范例成为支流;
[*]援用范例合用于布局庞大,有承继、有多态,凸起举动的场所;
[*]参数传送情形也是思索的需要要素;
4.再论范例判等
范例的对照一般有Equals()、ReferenceEquals()和==/!=三种罕见的办法,个中中心的办法是Equals。我们晓得Equals是System.Object供应的虚办法,用于对照两个对象是不是指向不异的援用地点,.NETFramework的良多范例都完成了对Equals办法的重写,比方值范例的“鼻祖”System.ValueType就重载了Equal办法,以完成对实例数据的判等。因而,范例的判等也要从重写大概重载Equals等分歧的情形详细剖析,对值范例和援用范例判等,这三个办法各有区分,应多加注重。
4.1值范例判等
[*]Equals,System.ValueType重载了System.Object的Equals办法,用于完成对实例数据的判等。
[*]ReferenceEquals,对值范例使用ReferenceEquals将永久前往false。
[*]==,未重载的==的值范例,将对照两个值是不是“按位”相称。
4.2援用范例判等
[*]Equals,次要有两种办法,以下
publicvirtualboolEquals(objectobj);
publicstaticboolEquals(objectobjA,objectobjB);
一种是虚办法,默许为援用地点对照;而静态办法,假如objA是与objB不异的实例,大概假如二者均为空援用,大概假如objA.Equals(objB)前往true,则为true;不然为false。.NET的年夜部分类都重写了Equals办法,因而判等的前往值要依据详细的重写情形决意。
[*]ReferenceEquals,静态办法,只能用于援用范例,用于对照两个实例对象是不是指向统一援用地点。
[*]==,默许为援用地点对照,一般举行完成了==的重载,未重载==的援用范例将对照两个对象是不是援用地点,同等于援用范例的Equals办法。因而,良多的.NET类完成了对==操纵符的重载,比方System.String的==操纵符就是对照两个字符串是不是不异。而==和equals办法的次要区分,在于多态体现上,==是被重载,而Equals是重写。
有需要在自界说的范例中,完成对Equals和==的重写大概重载,以进步功能和针对性剖析。
5.再论范例转换
范例转换是引发体系非常一个主要的要素之一,因而在有需要在这个主题里做以复杂的总结,我们不力图照应周全,可是追往模棱两可。罕见的范例转换包含:
[*]隐式转换:由初级范例项初级范例的转换历程。次要包含:值范例的隐式转换,次要是数值范例等基础范例的隐式转换;援用范例的隐式转换,次要是派生类向基类的转换;值范例和援用范例的山人转换,次要指装箱和拆箱转换。
[*]显现转换:也叫强迫范例转换。可是转换历程不克不及包管数据的完全性,大概引发必定的精度丧失大概引发不成知的非常产生。转换的格局为,比方:inta=(int)(b+2.02);
(type)(变量、表达式)
[*]值范例与援用范例的装箱与拆箱是.NET中最主要的范例转换,不得当的转换操纵会引发功能的极年夜消耗,因而我们将以专门的主题来会商。
[*]以is和as操纵符举行范例的平安转换,详见自己拙作《第一回:恩仇情仇:is和as》。
[*]System.Convert类界说了完成基础范例转换的便利完成。
[*]除string之外的其他范例都有Parse办法,用于将字符串范例转换为对应的基础范例;
[*]利用explicit大概implicit举行用户自界说范例转换,次要给用户进步自界说的范例转换完成体例,以完成更有目标的转换操纵,转换格局为,比方:
static会见润色操纵符转换润色操纵符operator范例(参数列表);publicStudent
{
//
<br>
staticpublicexpliciteopertatorStudent(stringname,intage)
{
returnnewStudent(name,age);
}
//
<br>
}个中,一切的转换都必需是static的。
6.结论
如今,我们从几个角度延长了上回对值范例和援用范例的剖析,正如本文开首所言,对范例的掌控另有良多能够发掘的要点,可是以偏责备的举措我以为仍是可取的,特别是在手艺寻找的过程当中,力图八面玲珑的做法并非功德。以上的几个角度,我以为是对值范例和援用范例掌控的必经之路,不然在实践的体系开辟中经常会在微小的中央栽跟头,摸不着思想。
咀嚼范例,我们以使用为要点撬开值范例和援用范例的礼貌与周遭。
咀嚼范例,我们将以示例为导航,开动一个层面的深切剖析,下回《第十回:咀嚼范例---值范例与援用范例(下)-使用征途》我们再会。
参考文献
(USA)JeffreyRichter,AppliedMicrosoft.NETFrameworkProgramming
(USA)DavidChappell,Understanding.NET
主流网站开发语言之PHP:PHP的全名非常有趣,它是一个巢状的缩写名称——“PHP:HypertextPreprocessor”,打开缩写还是缩写。PHP是一种HTML内嵌式的语言(就像上面讲的ASP那样)。而PHP独特的语法混合了C,Java,Perl以及PHP式的新语法。它可以比CGI或者Perl更快速地执行动态网页。 asp.net最主要特性包括:◆编程代码更简洁◆网站可实现的功能更强大◆运行效率高◆节省服务器的动作资源 ASP.NET可以无缝地与WYSIWYGHTML编辑器和其他编程工具(包括MicrosoftVisualStudio.NET)一起工作。这不仅使得Web开发更加方便,而且还能提供这些工具必须提供的所有优点,包括开发人员可以用来将服务器控件拖放到Web页的GUI和完全集成的调试支持。微软为ASP.net设计了这样一些策略:易于写出结构清晰的代码、代码易于重用和共享、可用编译类语言编写等等,目的是让程序员更容易开发出Web应用,满足计算向Web转移的战略需要。 ASP.Net和ASP的最大区别在于编程思维的转换,而不仅仅在于功能的增强。ASP使用VBS/JS这样的脚本语言混合html来编程,而那些脚本语言属于弱类型、面向结构的编程语言,而非面向对象。 那么,ASP.Net有哪些改进呢? 大哥拜托,Java在95年就出来了,微软垄断个妹啊,服务器市场微软完全是后后来者,当年都是Unix的市场,现在被WindowsServer和Linux抢下大片,包括数据库也一样。 ASP.net的速度是ASP不能比拟的。ASP.net是编译语言,所以,当第一次加载的时候,它会把所有的程序进行编译(其中包括worker进程,还有对语法进行编译,形成一个程序集),当程序编译后,执行速度几乎为0。 比如封装性、继承性、多态性等等,这就解决了刚才谈到的ASP的那些弱点。封装性使得代码逻辑清晰,易于管理,并且应用到ASP.Net上就可以使业务逻辑和Html页面分离,这样无论页面原型如何改变。 主流网站开发语言之ASP:ASP是微软(Microsoft)所开发的一种后台脚本语言,它的语法和VisualBASIC类似,可以像SSI(ServerSideInclude)那样把后台脚本代码内嵌到HTML页面中。虽然ASP简单易用,但是它自身存在着许多缺陷,最重要的就是安全性问题。 对于中小项目来说.net技术是完全可以胜任,但为什么现在大型公司或网站都选择php或java呢?就是因为微软不够开放,没有提供从硬件到应用服务器再到业务应用的整套解决方案。
页:
[1]