知识大全 C#锐利体验之第六讲 方法

Posted

篇首语:最聪明的处世之术是,既对世俗投以白眼,又与其同流合污。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 C#锐利体验之第六讲 方法相关的知识,希望对你有一定的参考价值。

C#锐利体验之第六讲 方法  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

  方法又称成员函数(Member Function) 集中体现了类或对象的行为 方法同样分为静态方法和实例方法 静态方法只可以操作静态域 而实例方法既可以操作实例域 也可以操作静态域 虽然这不被推荐 但在某些特殊的情况下会显得很有用 方法也有如域一样的 种存取修饰符 public protected internal protected internal private 它们的意义如前所述

  方法参数

  方法的参数是个值得特别注意的地方 方法的参数传递有四种类型 传值(by value) 传址(by reference) 输出参数(by output) 数组参数(by array) 传值参数无需额外的修饰符 传址参数需要修饰符ref 输出参数需要修饰符out 数组参数需要修饰符params 传值参数在方法调用过程中如果改变了参数的值 那么传入方法的参数在方法调用完成以后并不因此而改变 而是保留原来传入时的值 传址参数恰恰相反 如果方法调用过程改变了参数的值 那么传入方法的参数在调用完成以后也随之改变 实际上从名称上我们可以清楚地看出两者的含义 传值参数传递的是调用参数的一份拷贝 而传址参数传递的是调用参数的内存地址 该参数在方法内外指向的是同一个存储位置 看下面的例子及其输出

  using System;class Teststatic void Swap(ref int x ref int y) int temp = x;x = y;y = temp;static void Swap(int x int y) int temp = x;x = y;y = temp;static void Main() int i = j = ;Swap(ref i ref j);Console WriteLine( i = j = i j);Swap(i j);Console WriteLine( i = j = i j);程序经编译后执行输出

  i = j = i = j = 我们可以清楚地看到两个交换函数Swap()由于参数的差别 传值与传址 而得到不同的调用结果 注意传址参数的方法调用无论在声明时还是调用时都要加上ref修饰符

  笼统地说传值不会改变参数的值在有些情况下是错误的 我们看下面一个例子

  using System;class Elementpublic int Number= ;class Teststatic void Change(Element s)s Number= ;static void Main() Element e=new Element();Console WriteLine(e Number);Change(e);Console WriteLine(e Number);程序经编译后执行输出

   我们看到即使传值方式仍然改变了类型为Element类的对象t 但严格意义上讲 我们是改变了对象t的域 而非对象t本身 我们再看下面的例子

  using System;class Elementpublic int Number= ;class Teststatic void Change(Element s)Element r=new Element();r Number= ;s=r;static void Main() Element e=new Element();Console WriteLine(e Number);Change(e);Console WriteLine(e Number);程序经编译后执行输出

   传值方式根本没有改变类型为Element类的对象t!实际上 如果我们能够理解类这一C#中的引用类型(reference type)的特性 我们便能看出上面两个例子差别!在传值过程中 引用类型本身不会改变(t不会改变) 但引用类型内含的域却会改变(t Number改变了)!C#语言的引用类型有 object类型(包括系统内建的class类型和用户自建的class类型 继承自object类型) string类型 interface类型 array类型 delegate类型 它们在传值调用中都有上面两个例子展示的特性

  在传值和传址情况下 C#强制要求参数在传入之前由用户明确初始化 否则编译器报错!但我们如果有一个并不依赖于参数初值的函数 我们只是需要函数返回时得到它的值是该怎么办呢?往往在我们的函数返回值不至一个时我们特别需要这种技巧 答案是用out修饰的输出参数 但需要记住输出参数与通常的函数返回值有一定的区别 函数返回值往往存在堆栈里 在返回时弹出 而输出参数需要用户预先制定存储位置 也就是用户需要提前声明变量 当然也可以初始化 看下面的例子

  using System;class Teststatic void ResoluteName(string fullname out string firstname out string lastname) string[] strArray=fullname Split(new char[] );firstname=strArray[ ];lastname=strArray[ ];public static void Main() string MyName= Cornfield Lee ;string MyFirstName MyLastName;ResoluteName(MyName out MyFirstName out MyLastName);Console WriteLine( My first name: My last name: MyFirstName MyLastName);程序经编译后执行输出

  My first name: Cornfield My last name: Lee在函数体内所有输出参数必须被赋值 否则编译器报错!out修饰符同样应该应用在函数声明和调用两个地方 除了充当返回值这一特殊的功能外 out修饰符ref修饰符有很相似的地方 传址 我们可以看出C#完全摈弃了传统C/C++语言赋予程序员莫大的自由度 毕竟C#是用来开发高效的下一代网络平台 安全性 包括系统安全(系统结构的设计)和工程安全(避免程序员经常犯的错误)是它设计时的重要考虑 当然我们看到C#并没有因为安全性而丧失多少语言的性能 这正是C#的卓越之处 Sharp 之处!

  数组参数也是我们经常用到的一个地方 传递大量的数组集合参数 我们先看下面的例子

  using System;class Teststatic int Sum(params int[] args)int s= ;foreach(int n in args)s+=n;return s;static void Main() int[] var=new int[] ;Console WriteLine( The Sum: +Sum(var));Console WriteLine( The Sum: +Sum( ));程序经编译后执行输出

  The Sum: The Sum: 可以看出 数组参数可以是数组如 var 也可以是能够隐式转化为数组的参数如 这为我们的程序提供了很高的扩展性

  同名方法参数的不同会导致方法出现多态现象 这又叫重载(overloading)方法 需要指出的是编译器是在编译时便绑定了方法和方法调用 只能通过参数的不同来重载方法 其他的不同(如返回值)不能为编译器提供有效的重载信息

  方法继承第一等的面向对象机制为C#的方法引入了virtual override sealed abstract四种修饰符来提供不同的继承需求 类的虚方法是可以在该类的继承自类中改变其实现的方法 当然这种改变仅限于方法体的改变 而非方法头(方法声明)的改变 被子类改变的虚方法必须在方法头加上override来表示 当一个虚方法被调用时 该类的实例 亦即对象的运行时类型(run time type)来决定哪个方法体被调用 我们看下面的例子

  using System;class Parentpublic void F() Console WriteLine( Parent F ); public virtual void G() Console WriteLine( Parent G ); class Child: Parentnew public void F() Console WriteLine( Child F ); public override void G() Console WriteLine( Child G ); class Teststatic void Main() Child b = new Child();Parent a = b;a F();b F();a G();b G();程序经编译后执行输出

  Parent FChild FChild GChild G我们可以看到class Child中F()方法的声明采取了重写(new)的办法来屏蔽class Parent中的非虚方法F()的声明 而G()方法就采用了覆蓋(override)的办法来提供方法的多态机制 需要注意的是重写(new)方法和覆蓋(override)方法的不同 从本质上讲重写方法是编译时绑定 而覆蓋方法是运行时绑定 值得指出的是虚方法不可以是静态方法 也就是说不可以用static和virtual同时修饰一个方法 这由它的运行时类型辨析机制所决定 override必须和virtual配合使用 当然也不能和static同时使用

  那么我们如果在一个类的继承体系中不想再使一个虚方法被覆蓋 我们该怎样做呢?答案是sealed override (密封覆蓋) 我们将sealed和override同时修饰一个虚方法便可以达到这种目的 sealed override public void F() 注意这里一定是sealed和override同时使用 也一定是密封覆蓋一个虚方法 或者一个被覆蓋(而不是密封覆蓋)了的虚方法 密封一个非虚方法是没有意义的 也是错误的 看下面的例子

  //sealed cs// csc /t:library sealed csusing System;class Parentpublic virtual void F() Console WriteLine( Parent F );public virtual void G() Console WriteLine( Parent G );class Child: Parentsealed override public void F() Console WriteLine( Child F ); override public void G() Console WriteLine( Child G ); class Grandson: Childoverride public void G() Console WriteLine( Grandson G ); 抽象(abstract)方法在逻辑上类似于虚方法 只是不能像虚方法那样被调用 而只是一个接口的声明而非实现 抽象方法没有类似于…这样的方法实现 也不允许这样做 抽象方法同样不能是静态的 含有抽象方法的类一定是抽象类 也一定要加abstract类修饰符 但抽象类并不一定要含有抽象方法 继承含有抽象方法的抽象类的子类必须覆蓋并实现(直接使用override)该方法 或者组合使用abstract override使之继续抽象 或者不提供任何覆蓋和实现 后两者的行为是一样的 看下面的例子

  //abstract cs// csc /t:library abstract csusing System;abstract class Parentpublic abstract void F();public abstract void G();abstract class Child: Parentpublic abstract override void F();abstract class Grandson: Childpublic override void F()Console WriteLine( Grandson F );public override void G()Console WriteLine( Grandson G );抽象方法可以抽象一个继承来的虚方法 我们看下面的例子

  //abstract cs// csc /t:library abstract csusing System;class Parentpublic virtual void Method()Console WriteLine( Parent Method );abstract class Child: Parentpublic abstract override void Method();abstract class Grandson: Childpublic override void Method()Console WriteLine( Grandson Method );归根结底 我们抓住了运行时绑定和编译时绑定的基本机理 我们便能看透方法呈现出的种种overload virtual override sealed abstract等形态 我们才能运用好方法这一利器!

  外部方法

  C#引入了extern修饰符来表示外部方法 外部方法是用C#以外的语言实现的方法如Win API函数 如前所是外部方法不能是抽象方法 我们看下面的一个例子

  using System;using System Runtime InteropServices;class MyClass[DllImport( user dll )]static extern int MessageBoxA(int hWnd string msg string caption int type);public static void Main() MessageBoxA( Hello World! This is called from a C# app! );程序经编译后执行输出

相关参考

知识大全 十天学会ASP.net之第六天

十天学会ASP.net之第六天  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  学习目的学会读取数

知识大全 十天学会ASP.net之第二天

十天学会ASP.net之第二天  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  学习目的掌握C#的

知识大全 C#体验Microsoft.NET平台基础构造

C#体验Microsoft.NET平台基础构造  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!抛开M

知识大全 十天学会ASP.net之第一天

十天学会ASP.net之第一天  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  我认为ASPNET

知识大全 十天学会ASP.net之第七天

十天学会ASP.net之第七天  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  学习目的学会添加删

知识大全 十天学会ASP.net之第十天

十天学会ASP.net之第十天  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  学习目的学会SES

知识大全 十天学会ASP.net之第四天

十天学会ASP.net之第四天  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  学习目的掌握WEB

知识大全 十天学会ASP.net之第五天

十天学会ASP.net之第五天  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  学习目的学会连接两

知识大全 十天学会ASP.net之第三天

十天学会ASP.net之第三天  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  学习目的掌握WEB

知识大全 十天学会ASP.net之第八天

十天学会ASP.net之第八天  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  学习目的初步掌握D