C#學習基礎------方法

方法
方法在類中用於執行計算或其它行為的成員.聲明格式:
method-header
  method-body
其中方法頭method-header的格式:
attributes method-modifiers return-type member-name (formal-parameter-list)
傳遞給方法的參數在方法的形式參數表formal-parameter-list中聲明
在方法的聲明中,至少應包括方法名稱,修飾符和參數類型,返回值和參數名則不是必須的.
注意:方法名member-name不應與同一個類中的其它方法同名,也不能與類中的其它成員名稱

相同.
修飾符
方法的修飾符method-modifier可以是:
new
public
protected
internal
private
static
virtual
sealed
override
abstract
extern
對於使用了atstract和extern修飾符的方法,方法的執行體method-body僅僅只有一個簡單

的分號.其它所有的方法執行體中應包含調用該方法所需要執行的語句.
返回值
方法的返回值的類型可以是合法的C#的數據類型.C#在方法的執行部分通過return語句得到

返回值,如
using System;
class Test
{
  public int max(int x,int y)
  {
    if(x>y)
      return x;
    else
      return y;
  }
}
public void Main()
{
  Console.WriteLine("the max of 6 and 8 is:{0}",max(6,8));
}
如果在return後不跟隨任何值,方法返回值是void型的.

方法中的參數
C#中方法的參數有四种類型:
值參數,不含任何修飾符.
引用型參數,以ref修飾符聲明.
輸出參數,以out修飾符聲明.
數組型參數,以params修飾符聲明.
值參數
當利用值向方法傳遞參數時,編譯程序給實參的值做一份拷貝,並且將此拷貝傳遞給該方法.

被調用的方法不會修改內存中實參的值,所以使用值參數時,可以保證實際值是安全的.
下面的例子可以說明這個問題
using system;
class Test
{
  static void Swap(int x,int y)
  {
    int temp=x;
    x=y;
    y=temp;
  }
  static void Main()
  {
    int i=1,j=2;
    Swap(i,j);
    Console.WriteLine("i={0},j={1}",i,j);
  }
}
程序輸出的結果是:
i=1,j=2
程序並沒有達到交換的目的.

引用型參數
和值參不同的是,引用型參數並不開辟新的內存區域.當利用引用型參數向方法傳遞形參時,

編譯程序將把實際值在內存中的地址傳遞給方法.
下面的例子有說明這個
using System;
class Test
{
  static void Swap(ref int x,ref 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);
  }
}
程序運行的輸出結果是:
i=2,j=1
在方法中使用引用型參數,會經常可能多個變量名指向同一處內存地址.見下面的例子:
using System;
using System.Collections.Generic;
using System.Windows.Forms;

namespace WindowsApplication2
{
    class A
    {
        public string s="ssss";
        void F(ref string a, ref string b)
        {
            s = "One";
            a = "Two";
            b = "Three";
        }
        public void G()
        {
            F(ref s, ref s);
        }
        public void R()
        {
            Console.WriteLine("S:{0}", s);
        }
    }
    class T
    {
        public static void Main()
        {
            A a=new A();
            a.G();
            a.R();
        }
    }
}
程序運行的結果是
S:Three
在方法G對F的調用過程中,S的引用被同時傳遞給了a和b.此時,s,a,b同時指向了同一塊內存

區域.
輸出參數
與引用型參數類似,輸出型參數也不開辟新的內存區域,與引用型參數的差別在於,調用方法

前無需對變量進行初始化.輸出型參數用於傳遞方法返回數據.
out修飾符後應跟隨與形參的類型相同的類型聲明.在方法返回後,傳遞的變量被認為經過了

初始化.
using System;
class Test
{
  static void SplitPath(string path,out string dir,out string name)
  {
    int i=path.Length;
    while(i>0)
    {
      char ch=path[i-1];
      if(ch=='\\' || ch=='/' || ch==':') break;
      i--;
    }
    dir=path.Substring(0,i);
    name=path.Substring(i);
  }
  static void Main()
  {
    string dir,name;
    SplitPath("c:\\Window\\System\\hello.txt",out dir,out name);
    Console.WriteLine(dir);
    Console.WriteLine(name);
  }
}
程序輸出結果:
c:\Windwo\System\
hello.txt
我們看到,變量dir和name在傳遞給SplitPath之前並未初始化,在調用之後它們則有了明確

的值.
數組型參數
如果形參表中包含了數組型參數,那麼它必須在參數表中位於最後.另外,參數只允許是一維

數組.比如,string[]和string[][]類型都可以作為數組型參數,而string[,]則不能.最後數

組型參數不能再有ref和out修飾符.
using System;
class Test
{
  static void F(params int[] args)
  {
    Console.WriteLine("Array contains {0} elements:",args.Length);
    foreach (int i in args) Console.Write("{0},",i);
    Console.WriteLine();
  }
  public static void Main()
  {
    int[] a={1,2,3};
    F(a);
    F(10,20,30,40);
    F();
  }
}
程序運行結果:
Array contains 3 elements:
1,2,3,
Array contains 4 elements:
10,20,30,40,
Array contains 0 elements:

靜態和非靜態的方法
C#的類定義中可以包含兩种方法:靜態的和非靜態的.使用了static修飾符的方法為靜態方

法,反之則是非靜態的.
靜態方法是一种特殊的成員方法,它不屬於類的某一個具體的實例.非靜態方法可以訪問類

中的任何成員,而靜態方法只能訪問類中的靜態成員.
下面這個列子說明這一點.
class A
{
  int x;
  static int y;
  static int F()
  {
    x=1; //錯誤,不允許訪問
    y=2; //正確,允許訪問
  }
}
在這個類定議中,靜態方法F()可以訪問類中靜態成員s,但不能訪問非靜態的成員x.這是因

為,x作為非靜態成員,在類的每個實例中都占有一個存儲(或者說有一個副本),而靜態方法

是類所共享的,它無法判斷出當前的x屬於那個類的實例.所以不知道應該到內存的哪個地址

去讀取當前x的值.而y是靜態成員,所有類的實例都公用一個副本,靜態方法F使用它就不存

什麼問題.
是不是靜態方法就無法識別類的實例了呢?答案:不是.
我下面看一下有關windows窗口的例子
using System;
class Window
{
  public string m_caption;  //窗口的標題
  public bool IsActive;     //窗口是否被激活
  public handle m_handle;   //窗口的句柄
  public static int m_total;//當前打開的窗口數目
  public handle Window()
  {
    m_total++;
    return m_handle;
  }
  ~Window()
  {
    m_total--;
  }
  public static string GetWindowCaption(Window w)
  {
    return w.m_caption;
  }
}
分析一下上面例子中的代碼,每個窗口都有窗口標題m_caption,窗口句柄m_handle,窗口是

否激活IsActive三個非靜態的數據成員(窗口句柄是Windows操作系統中保存窗口相關信息

的一种數據結構,我們在這個例子中簡化了對句柄的使用).系統中總共打開窗口的數目

m_total作為一個靜態成員.每個窗口調用構造函數創建,這時候m_total的值加1.窗口關閉

或因為其它行為撤消時,通過析構函數m_total的值減1.我們要注意窗口類的靜態方法

GetWindowCaption(Window w).這里它通過參數w將對像傳遞給方法執行,這樣它就可以通過

具體實例中的類的實例指明調用的對像,這時它可以訪問具體實例中的成員,無論是靜態成

員還是非靜態成員.

方法的重載
類中兩個以上的方法(包括隱藏的繼承而來的方法),取的名字相同,只要使用的參數類型或

者參數個數不同,編譯器便知道在何种情況下應該調用哪個方法,這就叫做方法的重載.
下面看個例子
using System;
class Student
{
    public string s_name;
    public int s_age;
    public float s_weight;
    public Student(string n, int a, float w)
    {
        s_name = n;
        s_age = a;
        s_weight = w;
    }
    public int max(int x, int y)
    {
        if (x > y) return x;
        else return y;
    }
    public float max(float x, float y)
    {
        if (x > y) return x;
        else return y;
    }
}
class test
{
    public static void Main()
  {
    Student s1=new Student("Mike",21,70);
    Student s2=new Student("John",21,70);
    if (s1.max(s1.s_age, s2.s_age) == s1.s_age)
        Console.WriteLine("{0} age is bigger than {1}.", s1.s_name, s2.s_name);
    else
        Console.WriteLine("{0} age is smaller than {1}.", s1.s_name,

s2.s_name);
    if (s1.max(s1.s_weight, s2.s_weight) == s1.s_weight)
        Console.WriteLine("{0} age is bigger than {1}.", s1.s_name, s2.s_name);
    else
        Console.WriteLine("{0} age is smaller than {1}.", s1.s_name,

s2.s_name);
  }
}
程序運行的結果:
Mike age is bigger than John.
Mike age is bigger than John.

操作符重載
C#中,操作符重載總是在類中進行聲明,並且通過調用類的成員方法來實現.操作作重載的聲

明的格式為:
type  operator  operator-name  (formal-param-list)
C#中,下列操作符都是可以重載的
+  -  !  ~  ++  --  TRUE  FALSE
*  /  %  |  ^   <<  >>    ==   !=   >   <   >=  <=
但也有一些操作符是不允許進行重載的,如:
=,&&,||,?:,NEW,TYPEOF,SIZEOF,IS

一元操作符重載,一元操作符重載時操作符只作個用於一個對像,此時參數表為空,當前對像

作為操作符的單操作數.
下面我們舉一個角色類遊戲中經常遇到的例子.扮演的角色有內力,體力,經驗值,剩餘體力,

剩餘內力五個屬性,每當經驗值達到一定程度時,角色便會升級,體力,內力上升,剩餘體力和

內力補滿."升級"我們使用重載操作符"++"來實現.
using System;
class Player
{
    public int neili;
    public int tili;
    public int jingyan;
    public int neili_r;
    public int tili_r;
    public Player()
    {
        neili = 10;
        tili = 50;
        jingyan = 0;
        neili_r = 50;
        tili_r = 50;
    }
    public static Player operator ++(Player p)
    {
        p.neili = p.neili + 50;
        p.tili = p.tili + 100;
        p.neili_r = p.neili;
        p.tili_r = p.tili;
        return p;
    }
    public void Show()
    {
        Console.WriteLine("Tili:{0}", tili);
        Console.WriteLine("Jingyan:{0}", jingyan);
        Console.WriteLine("Neili:{0}", neili);
        Console.WriteLine("Tili_Full:{0}", tili_r);
        Console.WriteLine("Neili_Full:{0}", neili_r);
    }
}
class Test
{
    public static void Main()
    {
        Player man = new Player();
        man.Show();
        man++;
        Console.WriteLine("Now upgrading...");
        man.Show();
    }
}
程序輸出結果:
Tili:50
Jingyan:0
Neili:10
Tili_Full:50
Neili_Full:50
Now upgrading...
Tili:150
Jingyan:0
Neili:60
Tili_Full:150
Neili_Full:60

二元操作符重載
大多數情況下我們使用二元操作符重載.這時參數表中有一個參數,當前對像作為該操作符

的左操作數,參數作為操作符的右操作數.
下面是一個二元操作符重載的例子.即笛卡兒坐標相加.
using System;
class DKR
{
    public int x, y, z;
    public DKR(int vx, int vy, int vz)
    {
        x = vx;
        y = vy;
        z = vz;
    }
    public static DKR operator +(DKR d1, DKR d2)
    {
        DKR dkr = new DKR(0, 0, 0);
        dkr.x = d1.x + d2.x;
        dkr.y = d1.y + d2.y;
        dkr.z = d1.z + d2.z;
        return dkr;
    }
}
class Test
{
    public static void Main()
  {
    DKR d1 = new DKR(3,2,1);
    DKR d2 = new DKR(0, 6, 5);
    DKR d3 = d1 + d2;
    Console.WriteLine("The 3d location of d3 is:{0},{1},{2}",d3.x,d3.y,d3.z);
  }
}
程序輸出結果:
The 3d location of d3 is:3,8,6

posted @ 2007-10-31 16:35  Athrun  阅读(357)  评论(0编辑  收藏  举报