C#锐利体验(六)

2016-02-19 17:08 6 1 收藏

今天天气好晴朗处处好风光,好天气好开始,图老师又来和大家分享啦。下面给大家推荐C#锐利体验(六),希望大家看完后也有个好心情,快快行动吧!

【 tulaoshi.com - 编程语言 】

  第六讲 方法

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

  方法参数

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

using System;class Test{    static 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 = 1, j = 2;        Swap(ref i, ref j);        Console.WriteLine("i = {0}, j = {1}", i, j);        Swap(i,j);        Console.WriteLine("i = {0}, j = {1}", i, j);    }}

  程序经编译后执行输出:

i = 2, j = 1i = 2, j = 1 

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

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

using System;class Element{    public int Number=10;}class Test{    static void Change(Element s)    {        s.Number=100;    }    static void Main()    {        Element e=new Element();        Console.WriteLine(e.Number);        Change(e);        Console.WriteLine(e.Number);    }}

  程序经编译后执行输出:

  

10100 

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

using System;class Element{    public int Number=10;}class Test{    static void Change(Element s)    {        Element r=new Element();        r.Number=100;        s=r;    }    static void Main()    {        Element e=new Element();Console.WriteLine(e.Number);        Change(e);        Console.WriteLine(e.Number);    }}

  程序经编译后执行输出:

  

1010

(本文来源于图老师网站,更多请访问http://www.tulaoshi.com/bianchengyuyan/)

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

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

using System;class Test{    static void ResoluteName(string fullname,out string firstname,out string lastname)    {        string[] strArray=fullname.Split(new char[]{' '});        firstname=strArray[0];        lastname=strArray[1];    }    public static void Main()    {        string MyName="Cornfield Lee";        string MyFirstName,MyLastName;ResoluteName(MyName,out MyFirstName,out MyLastName);        Console.WriteLine("My first name: {0}, My last name: {1}",MyFirstName, MyLastName);    }}

  程序经编译后执行输出:

  

My first name: Cornfield, My last name: Lee 

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

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

  

using System;class Test{    static int Sum(params int[] args)    {        int s=0;        foreach(int n in args)        {            s+=n;        }        return s;    }    static void Main()    {        int[] var=new int[]{1,2,3,4,5};        Console.WriteLine("The Sum:"+Sum(var));        Console.WriteLine("The Sum:"+Sum(10,20,30,40,50));    }}

  程序经编译后执行输出:

  

The Sum:15The Sum:150 

(本文来源于图老师网站,更多请访问http://www.tulaoshi.com/bianchengyuyan/)

  可以看出,数组参数可以是数组如:var,也可以是能够隐式转化为数组的参数如:10,20,30,40,50。这为我们的程序提供了很高的扩展性。

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

  方法继承

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

  

using System;class Parent{    public void F() { Console.WriteLine("Parent.F"); }    public virtual void G() { Console.WriteLine("Parent.G"); }}class Child: Parent{    new public void F() { Console.WriteLine("Child.F"); }    public override void G() { Console.WriteLine("Child.G"); }}class Test{    static void Main()    {        Child b = new Child();        Parent a = b;        a.F();        b.F();        a.G();        b.G();    }}

来源:http://www.tulaoshi.com/n/20160219/1614330.html

延伸阅读
大家好,我是武汉华师的SUNWEN.现在是五月二号晚上19:27,由于闲着没事干,所有又写起来了.昨天照了十几张相,待会可以去取了,不知照片中的我是不是很帅,呵呵!现在我耳边正听着2000欧洲杯的曲子,所以比较激动.唉,身为我们院2000级足球队长的我,已经很久没有踢球了! 现在我要说的是C#中的版本处理.其实这是任何一个软件必须要考虑的问题.每个软件都...
如何控制好多个线程相互之间的联系,不产生冲突和重复,这需要用到互斥对象,即:System.Threading 命名空间中的 Mutex 类。 我们可以把Mutex看作一个出租车,乘客看作线程。乘客首先等车,然后上车,最后下车。当一个乘客在车上时,其他乘客就只有等他下车以后才可以上车。而线程与Mutex对象的关系也正是如此,线程使用Mutex.WaitOne()方法等...
如同java一样,在c#中写一个多线程应用是非常简单的,本章将介绍如何在c#种开发多线程程序。在.net中线程是由System.Threading 名字空间所定义的。所以你必须包含这个名字空间。   using System.Threading;    开始一个线程      System.Threading 名字空间的线程类描述了一个线程对象,通过使用类对象,你可以...
标签: ASP
       欢迎您加入C#的世界!      这一章将把您引进C#的天地,并回答一些相关的问题,如:您为什么要使用C#,C++和C#的主要有什么不同点,以及为什么C#使开发更容易而且还使您感到很有趣。      为什么是另外一种编程语言?      必须回答...
应该说,从 C/C++ 发展到 C#,进而到 Microsoft .NET Framework,对于习惯使用 C/C++ 的程序员来说是一次小小的打击。换句话说,C# 编程将带来翻天覆地的变化,不仅要完成范例转换,还要完成程序模型的重建以及其他各种令人难以捉摸的词组转变。但是,随着新一年的到来,不正是学习新编程语言的好时机吗? 我现在实在是抽不出时间教您如何使...

经验教程

931

收藏

33
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部