官术网_书友最值得收藏!

3章 C#面向?qū)ο蠡A(chǔ)

面向?qū)ο缶幊痰挠⑽暮?jiǎn)稱是OOP(Object Oriented Programming),該項(xiàng)技術(shù)是目前運(yùn)用最廣泛的程序化設(shè)計(jì)方法,幾乎已經(jīng)完全取代了過(guò)去的面向過(guò)程編程。C#從一誕生開始,就是為面向?qū)ο缶幊趟鶞?zhǔn)備的。類是面向?qū)ο缶幊痰暮诵牟考枋隽艘唤M具有相同特性和行為的對(duì)象。基于面向?qū)ο蟮膽?yīng)用程序,就是由幾個(gè)或幾十個(gè)甚至更多的類組成,且類之間總是保持著或多或少的關(guān)系。類其實(shí)也是數(shù)據(jù)類型,所以在面向?qū)ο缶幊讨谐绦騿T可以自定義數(shù)據(jù)類型,這和面向過(guò)程編程是有本質(zhì)區(qū)別的。

本章主要內(nèi)容:

● 類的定義

● 類的數(shù)據(jù)成員和函數(shù)成員

● 事件和委托

● 接口的使用

● 面向?qū)ο蟮娜筇卣?/p>

● 其他面向?qū)ο蟮闹黝}

3.1 類的基本概念

在C#中,類可以看成是一種數(shù)據(jù)結(jié)構(gòu),它自身封裝了數(shù)據(jù)成員和函數(shù)成員等。其中數(shù)據(jù)成員包括字段、常量和域等,而函數(shù)成員主要包括方法、屬性、事件、索引器和操作符等。本節(jié)將對(duì)類的結(jié)構(gòu)和用法進(jìn)行詳細(xì)說(shuō)明。

3.1.1 C#中的類定義

在C#中,用class關(guān)鍵字來(lái)定義類,基本結(jié)構(gòu)如下所示。

        [attributes] [modifiers] class identifier [:base-list]
         {
        class-body
        }

其中attributes表示附加的聲明信息,modifiers表示類的訪問(wèn)修飾符,identifier表示類的名稱,base-list表示繼承的基類和實(shí)現(xiàn)的接口的列表,基類在前,接口在后,且用逗號(hào)隔開。

在C#中,類的訪問(wèn)修飾符主要分為public、private、protected和internal。它們的具體用法如下所示。

        public:它具有最高的訪問(wèn)級(jí)別,對(duì)訪問(wèn)公共成員沒(méi)有限制;
        private:它的訪問(wèn)級(jí)別最低,僅限于它的包含類;
        protected:能在它的包含類或包含類的派生類中訪問(wèn);
        internal:只能在同一程序集的文件中。

原則上,一個(gè)類只能使用一種訪問(wèn)修飾符,但有一個(gè)特例需要注意,具體如下所示。

        protected internal:僅限于從包含類派生的當(dāng)前程序集或類型。

還有一些修飾符能與以上修飾符相結(jié)合,得到一些特殊的限制,比如abstract和sealed等,如下所示。

        public abstract:可以在任何地方訪問(wèn),但不能實(shí)例化,只能繼承;
        public sealed:可以在任何地方訪問(wèn),只能實(shí)例化,不能派生。

3.1.2 字段

字段實(shí)際上相當(dāng)于類的變量,它在類中的應(yīng)用十分廣泛,看一個(gè)簡(jiǎn)單的例子,如下面代碼所示。

        public class Car
        {
            public string Name;
            public string Color;
            public double Price;
        }
        Car car = new Car();
        car.Name="BMW";
        car.Color="White";
        car.Price=80000.00;

在上例中,定義了一個(gè)Car類,它包含了三個(gè)字段,分別為Name、Color和Price。通過(guò)在類的外部對(duì)該類進(jìn)行實(shí)例化,對(duì)類的字段進(jìn)行賦值。這里需要注意的是,類中的字段也必須要定義成public類型才能在類的外部被訪問(wèn)。

3.1.3 常量

常量在類中所處的地位和字段差不多,只是它不可變而已。通常,定義常量用關(guān)鍵字const,如下面代碼所示。

        public const int age = 25;

3.1.4 域

域的聲明過(guò)程和字段比較相似,但它們之間有一個(gè)很重要的區(qū)別,即域只能聲明在類的內(nèi)部,而不能聲明在類的方法的內(nèi)部。域分為實(shí)例域和靜態(tài)域,實(shí)例域只能通過(guò)類的實(shí)例進(jìn)行調(diào)用,而靜態(tài)域可以直接通過(guò)類名進(jìn)行調(diào)用。下面看一個(gè)例子,代碼如下。

        class Student
        {
            public static int count = 37;           //聲明域
            static void Main(string[] args)
          {
              Console.WriteLine("學(xué)生人數(shù)為:"+Student.count.ToString());
              Console.ReadKey();
          }
      }

運(yùn)行結(jié)果如圖3-1所示。

圖3-1 運(yùn)行結(jié)果圖

以上代碼聲明了一個(gè)靜態(tài)域count,因?yàn)槭庆o態(tài)的,所以它能直接用類名進(jìn)行調(diào)用。此外,域也可以分為公有域和私有域。公有域可以在類的外部被修改,而私有域(也稱為只讀域)不能在類的外部被修改,聲明私有域的關(guān)鍵字是readonly,如下面的例子所示。

        class Student
        {
            public readonly int count = 37;           //聲明私有域
            static void Main(string[] args)
            {
              Student sd = new Student();
              Console.WriteLine("學(xué)生人數(shù)為:"+sd.count++);
              Console.ReadKey();
            }
        }

如果試圖運(yùn)行該程序,會(huì)出現(xiàn)如圖3-2所示的錯(cuò)誤信息。

圖3-2 錯(cuò)誤列表

這是因?yàn)橛騝ount是私有域,用readonly關(guān)鍵字標(biāo)識(shí)的私有域不能在外部被修改。如果去掉readonly關(guān)鍵字,則count變?yōu)楣杏颍藭r(shí)運(yùn)行后輸出結(jié)果如圖3-3所示。

圖3-3 運(yùn)行結(jié)果

3.1.5 類的方法

在C#中,方法的定義與其他語(yǔ)言一樣,包括三個(gè)部分,分別為訪問(wèn)修飾符、輸入?yún)?shù)和返回類型。方法的訪問(wèn)修飾符的類型和類的差不多,如表3-1所示。

表3-1 方法修飾符

類的方法被創(chuàng)建以后,必須要被調(diào)用才有意義。下面的代碼是調(diào)用類的方法的例子。

        public abstract class Compute
        {
            public virtual int Method(int x, int y)
            {
              return x + y;
            }
        }
        public class Use:Compute
        {
            public override int Method(int x, int y)
            {
              return base.Method(x, y);
            }
            static void Main(string[] args)
            {
              Use use = new Use();
              Console.WriteLine(use.Method(2,3));
              Console.ReadKey();
            }
        }

上面的代碼中首先定義一個(gè)抽象類Compute,它只能被繼承,此外它包含了一個(gè)虛擬方法Method(),該方法只能在它的包含類的派生類中被重寫后才能使用。然后定義Compute類的派生類Use,并且在Use類中重寫Method()方法。最后通過(guò)實(shí)例化Use類,輸出結(jié)果,如圖3-4所示。

圖3-4 運(yùn)行結(jié)果

方法被調(diào)用時(shí),參數(shù)傳遞十分重要。同其他編程語(yǔ)言一樣,C#中方法的參數(shù)傳遞也分為值傳遞和引用傳遞。它們之間的區(qū)別比較難以理解,下面通過(guò)例子來(lái)說(shuō)明。

        public class Use
        {
            public int Method1(int x)
          {
            x=3*x;
            return x;
          }
          public int Method2(ref int x)
          {
              x=3*x;
              return x;
          }
          static void Main(string[] args)
          {
              Use use = new Use();
              int x = 2;
              Console.WriteLine("輸出結(jié)果是:" + use.Method2(ref x));   //輸出引用傳遞
                                                                        //的結(jié)果
              Console.WriteLine("輸出結(jié)果是:"+use.Method1(x));     //輸出值傳遞的結(jié)果
              Console.ReadKey();
          }

以上代碼主要定義了兩個(gè)方法,Method1()是值參數(shù)類型,而Method2()引用參數(shù)類型,最后輸出它們的結(jié)果,如圖3-5所示。

圖3-5 運(yùn)行結(jié)果

此時(shí),將兩個(gè)輸出語(yǔ)句的順序顛倒,具體如下所示。

        Console.WriteLine("輸出結(jié)果是:"+use.Method1(x));        //輸出值傳遞的結(jié)果
        Console.WriteLine("輸出結(jié)果是:" + use.Method2(ref x)); //輸出引用傳遞的結(jié)果

此時(shí)再看輸出結(jié)果,如圖3-6所示。

圖3-6 運(yùn)行結(jié)果

比較以上兩個(gè)輸出結(jié)果,發(fā)現(xiàn)并不相同。原因是引用參數(shù)使方法引用的是原來(lái)的變量,而值參數(shù)引用的僅是原來(lái)變量的副本。交換輸出語(yǔ)句前的程序中,因?yàn)橄日{(diào)用了引用參數(shù)傳遞,所以更改了原來(lái)的變量,使x從2變成了6,所以值傳遞的結(jié)果為18。相反,當(dāng)值傳遞先被調(diào)用時(shí),它并沒(méi)有改變?cè)瓉?lái)的變量,所以兩個(gè)輸出結(jié)果均為6。

3.1.6 類的屬性

類的屬性提供比較靈活的機(jī)制來(lái)讀取、編寫或計(jì)算私有字段的值,可以像使用公有數(shù)據(jù)成員一樣使用屬性。屬性必須要由訪問(wèn)器進(jìn)行讀寫,它的一般聲明格式如下所示。

        [attributes] [modifiers] type identifier
        {
        declaration
        }

其中attributes表示附加的聲明信息,modifiers表示修飾符,和類的方法的修飾符差不多,type表示屬性類型,declaration表示對(duì)屬性的讀寫操作。如下面的例子所示。

        class Fruit
        {
            private string name;
            public string Name
            {
              get
              {
                  return name;
              }
              set
              {
                  name = value;
              }
            }
            static void Main(string[] args)
            {
              Fruit fr = new Fruit();
              fr.Name = "Apple";
              Console.WriteLine("這種水果為:"+fr.Name);
              Console.ReadKey();
            }
        }

運(yùn)行結(jié)果如圖3-7所示。

圖3-7 運(yùn)行結(jié)果

屬性的一個(gè)重要特點(diǎn)是含有g(shù)et和set訪問(wèn)器,set用于寫,get用于讀。它們也可以缺省,只含有g(shù)et訪問(wèn)器的屬性為只讀屬性,只含有set訪問(wèn)器的屬性為只寫屬性。將上面的代碼替換為如下所示代碼。

        class Fruit
        {
            private string name;
            public string Name
            {
              get
              {
                  return name;
              }
            }
            static void Main(string[] args)
          {
              Fruit fr = new Fruit();
              fr.name = "Apple";
              Console.WriteLine("這種水果為:"+fr.Name);
              Console.ReadKey();
          }
      }

此時(shí)的Name為只讀屬性,所以必須要對(duì)name進(jìn)行賦值才能正確輸出結(jié)果,輸出結(jié)果與圖3-7一致。

3.1.7 類的索引器

索引器是C#所特有的類成員,它的主要作用是對(duì)象能向數(shù)組一樣被方便地引用。索引器的聲明與屬性的聲明比較類似,如下所示。

        Public type this[index]
        {
            get
            {
              //代碼
            }
            set
            {
              //代碼
            }
        }

索引器具有以下特點(diǎn)。

(1)索引器沒(méi)有具體的名字,需要用this關(guān)鍵字對(duì)對(duì)象進(jìn)行索引。this關(guān)鍵字指向被訪問(wèn)成員所在的當(dāng)前實(shí)例,可以在構(gòu)造函數(shù)和實(shí)例方法中實(shí)現(xiàn)對(duì)成員的訪問(wèn),但不能訪問(wèn)靜態(tài)成員。

(2)索引器不能定義為靜態(tài)的。

(3)索引器的參數(shù)index只能是傳值類型,不能出現(xiàn)ref和out關(guān)鍵字。

下面是一個(gè)關(guān)于索引器的例子。

        class Student
        {
            public string[] Name = new string[10];
            public Student()
            {
              for (int i = 0; i < 10; i++)
              {
                  Name[i] = i.ToString();
              }
            }
            public string this[int index]           //創(chuàng)建索引器
            {
              get
              {
                  string str;
                  if (index >= 0 && index < 10)
                  {
                      str = Name[index];
                  }
                  else
                  {
                      str = "null";
                  }
                  return str;
              }
              set
              {
                  if (index >= 0 && index < 10)
                  {
                      Name[index] = value;
                  }
              }
            }
            static void Main(string[] args)
            {
              Student sd = new Student();
              sd[3] = "zhangwei";
              sd[4] = "weiyi";
              sd[5] = "lirong";
              for (int i = 0; i < 12; i++)
              {
                  Console.WriteLine(sd[i]);
              }
              Console.ReadKey();
            }
        }

上面的代碼通過(guò)索引器實(shí)現(xiàn)了對(duì)Name數(shù)組的訪問(wèn),運(yùn)行結(jié)果如圖3-8所示。

圖3-8 運(yùn)行結(jié)果

3.1.8 類的構(gòu)造函數(shù)和析構(gòu)函數(shù)

類的構(gòu)造函數(shù)能被編譯器自動(dòng)執(zhí)行,它具有以下特點(diǎn)。

(1)構(gòu)造函數(shù)必須與類同名。

(2)構(gòu)造函數(shù)不能有返回類型。

(3)當(dāng)訪問(wèn)一個(gè)類時(shí),它的構(gòu)造函數(shù)最先被執(zhí)行。

(4)一個(gè)類可以有多個(gè)構(gòu)造函數(shù),如果沒(méi)有定義構(gòu)造函數(shù),系統(tǒng)會(huì)自動(dòng)生成一個(gè)默認(rèn)的構(gòu)造函數(shù)。

構(gòu)造函數(shù)又分為實(shí)例構(gòu)造函數(shù)和靜態(tài)構(gòu)造函數(shù),其區(qū)別如表3-2所示。

表3-2 實(shí)例構(gòu)造函數(shù)與靜態(tài)構(gòu)造函數(shù)

下面通過(guò)例子進(jìn)行說(shuō)明,示例代碼如下。

        class Student
        {
            public static int x;
            public int y;
            public int z;
            public int m;
            public int n;
            //構(gòu)造函數(shù)一
            public Student()
            {
              y = 2;
              z = 2;
            }
            //構(gòu)造函數(shù)二
            public Student(int m, int n)
            {
              this.m = m;
              this.n = n;
            }
            //構(gòu)造函數(shù)三
            static Student()
            {
              x = 5;
            }
            static void Main(string[] args)
            {
              Console.WriteLine("x="+Student.x);
              Student sd1 = new Student();
              Console.WriteLine("y={0}, z={1}", sd1.y, sd1.z);
              Student sd2 = new Student(3,3);
              Console.WriteLine("m={0}, n={1}", sd2.m, sd2.n);
              Console.ReadKey();
            }
        }

本例共為Student類創(chuàng)建了三個(gè)構(gòu)造函數(shù),其中構(gòu)造函數(shù)三是靜態(tài)構(gòu)造函數(shù)。例子運(yùn)行結(jié)果如圖3-9所示。

圖3-9 運(yùn)行結(jié)果

類的析構(gòu)函數(shù)與構(gòu)造函數(shù)的過(guò)程剛剛相反,它主要用于銷毀類的實(shí)例。它不能帶有參數(shù),不能含有修飾符,不能被調(diào)用,且它也必須與類同名。為了區(qū)別于構(gòu)造函數(shù),通常在前面加符號(hào)“~”。其語(yǔ)法如下所示。

        class Student
            {
              ……
              ~Student()
              {
                ……
              }
        }

析構(gòu)函數(shù)通常會(huì)被自動(dòng)執(zhí)行,只有一些非常特殊的情況下才需要被用到,比如非托管資源的清理。

3.1.9 事件

事件相關(guān)知識(shí)的內(nèi)容太多,在本章的后面部分將用單獨(dú)一節(jié)進(jìn)行講解。

3.2 Visual Studio中的類向?qū)?/h3>

在Visual Studio 2008(以下簡(jiǎn)稱VS2008)中,提供了創(chuàng)建類和類的成員的快捷方式,在本節(jié)中將通過(guò)例子進(jìn)行詳細(xì)說(shuō)明。其創(chuàng)建步驟如下。

(1)打開VS2008,在D:\C#\ch3目錄下建立名為“ClassWizard”的控制臺(tái)應(yīng)用程序。打開“解決方案資源管理器”界面,右鍵單擊當(dāng)前工程“ClassWizard”,選擇“添加”—“新建項(xiàng)”命令,添加新類Book.cs,如圖3-10所示。

圖3-10 添加類

(2)選擇“視圖”—“類視圖”菜單,如圖3-11所示。

圖3-11 類視圖

此時(shí)可以看出當(dāng)前工程的類的結(jié)構(gòu)圖,包含兩個(gè)類,Book類和Program類,其中Book類是剛被創(chuàng)建的,而Program類是隨工程一起被創(chuàng)建的。在圖3-11中,下半部分窗格主要是顯示被選中類的具體成員。因?yàn)锽ook類是剛被創(chuàng)建的,所以它不含有任何成員。

(3)現(xiàn)在開始為Book類添加成員,在圖3-11中,右鍵單擊“Book”,選擇“查看類關(guān)系圖”命令,彈出如圖3-12所示的對(duì)話框。右鍵單擊空白處,選擇“添加”命令,其菜單如圖3-13所示。

圖3-12 類的關(guān)系圖

圖3-13 添加類的成員

(4)為Book類添加一個(gè)bookname字段,其屬性設(shè)置如圖3-14所示;然后添加一個(gè)Price屬性,如圖3-15所示。

圖3-14 添加字段

圖3-15 添加屬性

(5)接著再添加方法Count,如圖3-16所示。

圖3-16 添加方法

(6)添加完以上成員后,在“解決方案資源管理器”下打開Book.cs,代碼如下所示。

        class Book
        {
            private string[] bookname;
            public double Price
            {
              get
              {
                  throw new System.NotImplementedException();
              }
              set
              {
              }
            }
            public double Count()
            {
              throw new System.NotImplementedException();
            }
        }

從以上代碼可以看出,bookname字段、Price屬性和Count方法已經(jīng)添加到Book類中。其中.NotImplementedException()表示無(wú)法實(shí)現(xiàn)請(qǐng)求的方法或操作時(shí)引發(fā)的異常。將上面的代碼替換為如下所示代碼。

        class Book
        {
            //字段
            public string[] bookname = new string[4];
            public double price;
            //屬性
            public double Price
            {
              get
              {
                  return price;
              }
              set
              {
                  price = value;
              }
          }
          //方法
          public double Count(double Price)
          {
              Price = Price * 0.8;
              return Price;
          }
        }

在Main()函數(shù)中添加如下代碼。

        Book book = new Book();
        book.bookname[0] = "C# Programming";
        book.bookname[1] = "C++ Programming";
        book.bookname[2] = "C Programming";
        book.bookname[3] = "Java Programming";
        for (int i = 0; i < 4; i++)
        {
            Console.WriteLine("書名:" + book.bookname[i]);
            Console.WriteLine("原價(jià):");
            string s = Console.ReadLine();
            Console.WriteLine("打折后的價(jià)格:");
            Console.WriteLine(book.Count(Convert.ToDouble(s)));
        }
        Console.ReadKey();

程序運(yùn)行結(jié)果如圖3-17所示。

圖3-17 程序運(yùn)行結(jié)果

本例主要是通過(guò)VS2008中的類向?qū)?shí)現(xiàn)了類成員的添加,完成的功能是將Book類中的書名,書的原價(jià)和書打折后的價(jià)格輸出。

3.3 事件和委托

事件是C#中的又一個(gè)重要概念,在發(fā)生其他類或?qū)ο笮枰P(guān)注的事情時(shí),本類或?qū)ο罂梢酝ㄟ^(guò)事件來(lái)通知它們。發(fā)送事件的類稱為事件的發(fā)送者,而接收事件的類稱為事件的訂閱戶。

3.3.1 委托

委托是事件應(yīng)用過(guò)程中必不可少的一個(gè)環(huán)節(jié),委托首先是在Visual J++中提出的,后來(lái)被C#引用。如果一個(gè)類需要調(diào)用另一個(gè)類的方法,可以有三種方式,即實(shí)例方式、靜態(tài)方式和委托方式。應(yīng)用委托調(diào)用方法的流程如圖3-18所示。

圖3-18 委托使用流程圖

下面通過(guò)一個(gè)例子來(lái)說(shuō)明委托的具體用法。打開VS2008,在D:\C#\ch3目錄下建立名為DelegateTest的控制臺(tái)應(yīng)用程序。打開工程,添加如下代碼。

        class Test
        {
            public delegate void Mydelegate(string str);       //聲明委托
            public  int s = 3;
            public  void Method1(string str)                    //方法一
            {
              s = 5;
            }
            public  void Method2(string str)                    //方法二
            {
              s = 7;
            }
            public void Call(Mydelegate d, string str)           //調(diào)用委托中的方法
            {
              d(str);
              Console.WriteLine(str);
            }
            static void Main(string[] args)
            {
              Test test = new Test();
              Mydelegate d1 = new Mydelegate(test.Method1);   //在委托中包含方法一
              Mydelegate d2 = new Mydelegate(test.Method2);   //在委托中包含方法二
              test.Call(d2, "成功調(diào)用了委托");
              Console.WriteLine("輸出結(jié)果:"+test.s.ToString());
              Console.ReadKey();
            }
        }

代碼說(shuō)明如下。

(1)首先需要定義委托,使用的關(guān)鍵字是delegate,代碼如下所示。

        public delegate void Mydelegate(string str);         //聲明委托

它的返回類型和參數(shù)必須要和它調(diào)用的方法的返回類型和參數(shù)相匹配。

(2)接下來(lái)是定義該委托需要調(diào)用的方法,本例定義了兩個(gè)方法,用于對(duì)字段s進(jìn)行不同的修改,如下所示。

        public  void Method1(string str)                    //方法一
          {
              s = 5;
          }
          public  void Method2(string str)                //方法二
          {
              s = 7;
          }

(3)創(chuàng)建委托對(duì)象,對(duì)聲明的方法進(jìn)行包含,如下所示。

        Test test = new Test();
        Mydelegate d1 = new Mydelegate(test.Method1);      //在委托中包含方法一
        Mydelegate d2 = new Mydelegate(test.Method2);      //在委托中包含方法二

(4)最后即是完成方法的調(diào)用,如下所示。

          public void Call(Mydelegate d, string str)          //調(diào)用委托中的方法
              {
                d(str);
                Console.WriteLine(str);
              }

這里使用了兩個(gè)參數(shù),第一個(gè)是創(chuàng)建的委托對(duì)象,它能直接通過(guò)要調(diào)用方法的參數(shù)完成對(duì)方法的調(diào)用,第二個(gè)參數(shù)是調(diào)用的方法的參數(shù)。程序的運(yùn)行結(jié)果如圖3-19所示。

圖3-19 運(yùn)行結(jié)果

3.3.2 委托的事件處理程序

前面提到,事件需要訂閱者,當(dāng)事件發(fā)生時(shí),訂閱者會(huì)給出相應(yīng)的事件處理程序。事件處理程序本身是簡(jiǎn)單的函數(shù)形式,它的參數(shù)和返回類型必須和調(diào)用它的委托相匹配。委托在這里的作用是包含事件處理程序,當(dāng)事件被觸發(fā)時(shí),通過(guò)委托來(lái)執(zhí)行事件處理程序。下面通過(guò)例子進(jìn)行說(shuō)明,主要功能是通過(guò)在Class2中定義并觸發(fā)事件,在Class1中調(diào)用事件處理程序。

打開VS2008,在D:\C#\ch3目錄下建立名為EventTest的控制臺(tái)應(yīng)用程序,打開工程,添加如下所示代碼。

        namespace EventTest
        {
            //繼承
            public class MyEventArgs : EventArgs
            {
              public string str;
            }
            //聲明委托對(duì)象
            public delegate void MyEventHandler1(object sender, MyEventArgs e);
            class Class1
            {
              //創(chuàng)建委托對(duì)象并包含事件處理函數(shù)
              public Class1(Class2 class2)
              {
                  MyEventHandler1 mh1 = new MyEventHandler1(Method1);
                  //訂閱事件
                  class2.Event1 += mh1;
              }
              //事件處理函數(shù)
              public void Method1(object sender, MyEventArgs e)
              {
                  Console.WriteLine("事件處理結(jié)果:"+e.str);
              }
          }
          //通過(guò)委托來(lái)調(diào)用被包含的方法
          class Class2
          {
              //定義事件
              public event MyEventHandler1 Event1;
              //觸發(fā)事件
              public void mEvent1(MyEventArgs e)
              {
                  if (Event1 ! = null)
                  {
                    Event1(this, e);
                  }
              }
          }
          class Class3
          {
              static void Main(string[] args)
              {
                  Class2 class2 = new Class2();
                  Class1 class1 = new Class1(class2);
                  MyEventArgs e1 = new MyEventArgs();
                  e1.str = "aaa";
                  class2.mEvent1(e1);
                  Console.ReadKey();
              }
          }
        }

代碼說(shuō)明如下。

(1)首先還是需要定義委托,事件中的委托和普通委托有一定的區(qū)別,它的參數(shù)形式比較固定,如下所示。

        public delegate void MyEventHandler1(object sender, MyEventArgs e);

事件中的委托具有兩個(gè)參數(shù),第一個(gè)參數(shù)表示事件的觸發(fā)對(duì)象,第二個(gè)參數(shù)表示處理事件的對(duì)象,它是從EventArgs類繼承而來(lái),EventArgs類包含很多事件處理對(duì)象類,在GUI中比較常見,如鼠標(biāo)事件處理類MouseEventArgs。本例的MyEventArgs是從EventArgs中繼承而來(lái)(有關(guān)繼承的知識(shí)將會(huì)在本章后面部分講解),如下所示。

        public class MyEventArgs : EventArgs
            {
              public string str;
            }

(2)接下來(lái)需要在Class2中完成事件的聲明和觸發(fā),如下所示。

        class Class2
            {
              //定義事件
              public event MyEventHandler1 Event1;
              public void mEvent1(MyEventArgs e)
              {
                  if (Event1 ! = null)
                  {
                      //觸發(fā)事件
                      Event1(this, e);
                  }
              }
            }

(3)在Class1類中定閱事件并編寫事件處理程序,如下所示。

        class Class1
        {
            //創(chuàng)建委托對(duì)象并包含事件處理函數(shù)
            public Class1(Class2 class2)
            {
              MyEventHandler1 mh1 = new MyEventHandler1(Method1);
              //訂閱事件
              class2.Event1 += mh1;
            }
            //事件處理函數(shù)
            public void Method1(object sender, MyEventArgs e)
            {
              Console.WriteLine("事件處理結(jié)果:"+e.str);
            }
        }

在Class1中完成了Class2的Event1事件的訂閱,以上工作由委托mh1完成。相應(yīng)的事件處理代碼包含在Method1()中。

(4)最后,輸出事件處理結(jié)果,如下所示。

        Class2 class2 = new Class2();
        Class1 class1 = new Class1(class2);
        MyEventArgs e1 = new MyEventArgs();
        e1.str = "aaa";
        class2.mEvent1(e1);
        Console.ReadKey();

程序的運(yùn)行結(jié)果如圖3-20所示。

圖3-20 運(yùn)行結(jié)果

3.3.3 委托中的GUI事件

從上一節(jié)的例子可以看出,事件的應(yīng)用步驟是比較復(fù)雜的。在.NET Framework中,運(yùn)用事件最多的部分是GUI控件,比如Button的Click(單擊)事件。是不是每應(yīng)用一次事件就必須做出與上例相似的操作?答案是否定的。在GUI事件的應(yīng)用中,.NET Framework已經(jīng)完成了大量的工作,下面通過(guò)例子進(jìn)行說(shuō)明。

注意:以下例子會(huì)用到控件知識(shí),不懂控件的讀者可先跳過(guò)這部分。

打開VS2008,在D:\C#\ch3目錄下建立名為GUIEventTest的Windows應(yīng)用程序,打開工程,為當(dāng)前窗體添加一個(gè)Button控件。右鍵單擊該Button控件對(duì)象,選擇“屬性”,轉(zhuǎn)到“屬性”的“事件”窗口,如圖3-21所示。

圖3-21 事件窗口

從圖3-21可以看出,Button包含了很多事件,雙擊Click事件,窗口中顯示的代碼如下所示。

        private void button1_Click(object sender, EventArgs e)
        {
        }

button1_Click()為事件處理函數(shù),它具有兩個(gè)參數(shù),這在前面已經(jīng)講過(guò)。需要注意的是它使用的事件處理對(duì)象EventArgs類。此時(shí),打開Form1.Designer.cs,在有關(guān)Button的設(shè)計(jì)器代碼中有如下語(yǔ)句。

        this.button1.Click += new System.EventHandler(this.button1_Click);

可見,編譯器已經(jīng)訂閱好了該事件,讀者需要做的工作僅是向button1_Click()中添加程序執(zhí)行代碼。比如添加如下所示代碼。

        this.Text = "GUI事件";

完成對(duì)當(dāng)前窗體標(biāo)題的修改,運(yùn)行程序,結(jié)果如圖3-22所示。

圖3-22 運(yùn)行結(jié)果

本節(jié)主要介紹了C#中的事件處理機(jī)制及委托的用法。C#中的事件主要分為兩類,一類是GUI事件,.NET Framework為這類事件的應(yīng)用做了大量工作,它的使用較簡(jiǎn)單;另一類是非GUI事件,它的事件聲明、訂閱和處理都需要讀者自己編寫,使用比較復(fù)雜,但在一些場(chǎng)合它是很必要的。總的來(lái)說(shuō),事件具有以下特點(diǎn)。

(1)事件的發(fā)送者決定何時(shí)發(fā)送事件,事件的訂閱者決定執(zhí)行何種操作來(lái)響應(yīng)事件。

(2)一個(gè)事件可以同時(shí)有多個(gè)訂閱者,一個(gè)訂閱者可以響應(yīng)多個(gè)事件。

(3)沒(méi)有訂閱者的事件不會(huì)被調(diào)用。

(4)具有多個(gè)訂閱者的事件被觸發(fā)時(shí),會(huì)同步調(diào)用多個(gè)事件處理程序。

(5)在.NET Framework中,事件是基于EventHandler委托和EventArgs基類的。

通過(guò)本節(jié)的學(xué)習(xí),讀者應(yīng)該對(duì)事件有了一個(gè)比較初步的認(rèn)識(shí),在以后的章節(jié)中具體的應(yīng)用場(chǎng)合還會(huì)繼續(xù)講解事件。

3.4 面向?qū)ο蟮奶卣?/h3>

面向?qū)ο笾饕哂腥筇卣鳎蠢^承、多態(tài)和封裝。正因?yàn)檫@些機(jī)制的存在,才使得應(yīng)用程序變得更為簡(jiǎn)單和豐富多彩。本節(jié)將對(duì)以上三個(gè)特征進(jìn)行詳細(xì)介紹,此外還會(huì)提到面向?qū)ο笾辛硪粋€(gè)重要知識(shí)點(diǎn)——重載。

3.4.1 繼承

繼承是指一個(gè)類A能利用另一個(gè)類B的資源(包括屬性和方法等),其中B類被稱為基類(或父類),而A類被稱為派生類(或子類)。繼承的使用語(yǔ)法如下所示。

        public class A
        {
            public A{}
        }
        public B:A
        {
            public B{}
        }

類的繼承用符號(hào)“:”進(jìn)行標(biāo)識(shí),以上代碼定義了B類繼承于A類。如果B類繼承于A類,那么B類是否能訪問(wèn)A類中的全部成員?答案是否定的。這也就是下面要說(shuō)明的有關(guān)派生類在基類中的訪問(wèn)權(quán)限問(wèn)題。

(1)大多數(shù)而并非所有類都可以作為基類被繼承,比如帶有sealed修飾符的密封類不能被繼承。

(2)基類中只有兩種成員能被派生類訪問(wèn),包括public和protected類型的成員。其中,protected類型是專為派生類設(shè)計(jì)的,該類型的成員只能在派生類中進(jìn)行訪問(wèn)。

(3)在派生類中可以修改基類中的以下成員,包括虛擬成員(virtual)和抽象成員(abstract)。其中對(duì)虛擬成員的修改是在派生類中重寫該成員的執(zhí)行代碼;而對(duì)于抽象成員而言,它在基類中,沒(méi)有執(zhí)行代碼,需要在派生類中進(jìn)行添加。

可能有些讀者對(duì)于以上的講解感覺比較抽象,下面通過(guò)一個(gè)簡(jiǎn)單的例子進(jìn)行說(shuō)明。

打開VS2008,在D:\C#\ch3目錄下建立名為InheritTest的控制臺(tái)應(yīng)用程序。首先為當(dāng)前工程添加一個(gè)基類ClassF,代碼如下所示。

        class ClassF
        {
            //公有字段
            public string name="zhangwei";
            public string age;
            //公有屬性
            public  string Age
            {
              get
              {
                  return age;
              }
              set
              {
                  age = value;
              }
            }
            //虛擬方法
            public virtual double Income(double time)
            {
              double income = time * 100.0 + 2000.0;
              return income;
            }
        }

基類ClassF中,定義了一個(gè)公有字段,一個(gè)公有屬性和一個(gè)虛擬方法。下面是派生類ClassS的代碼。

        class ClassS:ClassF
        {
            //重寫虛擬方法
            public override double Income(double time)
            {
              double income = time * 100.0 + 3000.0;
              return income;
            }
            static void Main(string[] args)
            {
              ClassS cs = new ClassS();
              Console.WriteLine("姓名:");
              //繼承公有字段
              Console.WriteLine(cs.name);
              Console.WriteLine("工齡:");
              //繼承公有屬性
              cs.Age= Console.ReadLine();
              Console.WriteLine("工資:");
              //繼承虛擬方法
              Console.WriteLine(cs.Income(Convert.ToDouble(cs.Age)).ToString());
              Console.ReadKey();
          }
        }

在派生類ClassS中,調(diào)用了ClassF類中的公有字段name、公有屬性Age并重寫了虛擬方法Income()。此處,需要注意的是重寫虛擬方法需要用到override關(guān)鍵字。運(yùn)行程序,結(jié)果如圖3-23所示。

圖3-23 運(yùn)行結(jié)果

3.4.2 多態(tài)

多態(tài)是面向?qū)ο蟮挠忠粋€(gè)重要特征,它主要是指同一操作(如方法)作用于不同的類的實(shí)例,將產(chǎn)生不同的結(jié)果。多態(tài)主要是通過(guò)在派生類中對(duì)基類中的成員進(jìn)行替換或重定義完成。下面通過(guò)例子進(jìn)行說(shuō)明。

打開VS2008,在D:\C#\ch3目錄下建立名為PolymorphismTest的控制臺(tái)應(yīng)用程序。打開工程,添加如下代碼。

        //基類
        class ClassF
        {
            public virtual void Out()
            {
              Console.WriteLine("調(diào)用了基類中的方法!");
            }
        }
        //派生類1
        class ClassS1:ClassF
        {
            public override void Out()
            {
              Console.WriteLine("調(diào)用了派生類1中的方法!");
            }
        }
        //派生類2
        class ClassS2:ClassF
        {
            public override void Out()
          {
              Console.WriteLine("調(diào)用了派生類2中的方法!");
          }
      }
      //輸出結(jié)果
      class Test
      {
          static void Main(string[] args)
          {
              ClassF[] cf = new ClassF[3];
              cf[0] = new ClassF();
              cf[1] = new ClassS1();
              cf[2] = new ClassS2();
              foreach (ClassF c in cf)
              {
                c.Out();
              }
              Console.ReadKey();
          }
      }

上面代碼演示了多態(tài)性的實(shí)現(xiàn)過(guò)程,通過(guò)在兩個(gè)派生類中重寫基類中的虛方法實(shí)現(xiàn)。運(yùn)行結(jié)果如圖3-24所示。

圖3-24 運(yùn)行結(jié)果

如果要在派生類中隱藏基類中的非虛成員,可以使用new關(guān)鍵字。代碼如下所示。

        class ClassF
        {
            public  void Out()
            {
              Console.WriteLine("調(diào)用了基類中的方法!");
            }
        }
        class ClassS1:ClassF
        {
            public new void Out()
            {
              Console.WriteLine("調(diào)用了派生類1中的方法!");
            }
        }
        class Test
        {
            static void Main(string[] args)
            {
              ClassS1 cs = new ClassS1();
              Console.WriteLine(cs.Out().ToString());         //調(diào)用派生類中的方法
              Console.WriteLine(((ClassF)cs).Out().ToString()); //調(diào)用基類中的方法
              Console.ReadKey();
          }
        }

運(yùn)行結(jié)果如圖3-25所示。

圖3-25 運(yùn)行結(jié)果

上面代碼同樣也實(shí)現(xiàn)了多態(tài)的功能。多態(tài)本身理論比較難,本節(jié)僅通過(guò)兩個(gè)例子對(duì)簡(jiǎn)單的多態(tài)應(yīng)用進(jìn)行了說(shuō)明,多態(tài)的主要作用是提高代碼的重用性和簡(jiǎn)化程序結(jié)構(gòu)。

3.4.3 封裝

封裝是指將對(duì)象的信息進(jìn)行隱藏,只是提供一個(gè)訪問(wèn)接口,使它的使用者無(wú)法看到對(duì)象的具體信息。在類中,通過(guò)不同的修飾符能讓類的成員實(shí)現(xiàn)公開或隱藏。通過(guò)這些修飾符,類實(shí)現(xiàn)了很好的封裝。封裝的主要用途是防止數(shù)據(jù)受到意外的破壞,代碼如下所示。

        class Test
        {
            private int a;
            public int wr()
            {
              return a;
            }
            public void rd(int value)
            {
              a = value;
            }
        }
        class Program
        {
            static void Main(string[] args)
            {
              Test ts = new Test();
              ts.rd(3);
              ts.wr();
            }
        }

上面的代碼中,使Test類中的私有字段被訪問(wèn),但又很好地保護(hù)了它的數(shù)據(jù)不被破壞。封裝的內(nèi)容遠(yuǎn)不止這些,但基本思想是一致的。讀者應(yīng)該注意對(duì)封裝思想的學(xué)習(xí),這樣才能很好地應(yīng)用封裝的操作。

3.4.4 重載

重載是面向?qū)ο笾谐筇卣魍獾挠忠粋€(gè)重要知識(shí)點(diǎn),它是指在類中同名成員的不同定義。它的主要作用是使程序邏輯更加清晰。重載主要包括方法重載和運(yùn)算符重載,本節(jié)將通過(guò)例子對(duì)這兩者進(jìn)行詳細(xì)介紹。

3.4.5 方法重載

方法重載是C#中運(yùn)用最廣泛的一種重載方式,它是指在類中建立名稱相同但參數(shù)不同的方法。方法重載主要是為了解決操作同一類對(duì)象需要使用不同方法的問(wèn)題,如計(jì)算一類圖形的面積。圖形中包括矩形、圓和橢圓,它們的面積計(jì)算公式是不同的,這里就需要用到重載的概念。下面舉例進(jìn)行說(shuō)明。

打開VS2008,在D:\C#\ch3目錄下建立名為Overload1Test的控制臺(tái)應(yīng)用程序。打開工程,添加如下代碼。

        class Area
        {
            //計(jì)算矩形面積
            public int Count(int x, int y)
            {
              return x * y;
            }
            //計(jì)算圓面積
            public double Count(double r)
            {
              return Math.PI * r * r;
            }
            //計(jì)算橢圓面積
            public double Count(double a, double b)
            {
              return Math.PI * a * b;
            }
            static void Main(string[] args)
            {
              Area area =new Area();
              Console.WriteLine("矩形面積為:" + area.Count(4, 6));
              Console.WriteLine("圓的面積為:"+area.Count(3.4));
              Console.WriteLine("橢圓的面積為:"+area.Count(2.5,3.6));
              Console.ReadKey();
            }
        }

圖3-26 運(yùn)行結(jié)果

在Area類中分別定義了計(jì)算三種圖形面積的方法,三種方法具有相同的名稱,不同的參數(shù)和返回類型,實(shí)現(xiàn)了方法的重載。程序運(yùn)行結(jié)果如圖3-26所示。

3.4.6 運(yùn)算符重載

運(yùn)算符重載主要是為了在類中擴(kuò)展運(yùn)算符的功能,以完成一些特殊的操作。重載運(yùn)算符需要用到operator關(guān)鍵字。下面通過(guò)例子進(jìn)行說(shuō)明。

打開VS2008,在D:\C#\ch3目錄下建立名為Overload2test的控制臺(tái)應(yīng)用程序。打開工程,添加如下代碼。

        class Test
        {
            public int real;
            public int img;
            public Test(int real, int img)
            {
              this.real = real;
              this.img = img;
            }
            public static Test operator +(Test x, Test y)
            {
              return new Test(x.real+y.real, x.img+y.img);
            }
            static void Main(string[] args)
            {
              Test t1 = new Test(2,3);
              Test t2 = new Test(4,5);
              Test t3 = t1 + t2;
              Console.WriteLine("該復(fù)數(shù)的實(shí)部為:" + t3.real);
              Console.WriteLine("該復(fù)數(shù)的虛部為:" + t3.img);
              Console.ReadKey();
            }
        }

這是一個(gè)實(shí)現(xiàn)復(fù)數(shù)加法的經(jīng)典例子,通過(guò)在Test類中重載“+”運(yùn)算符實(shí)現(xiàn)了復(fù)數(shù)的加法。運(yùn)行結(jié)果如圖3-27所示。

圖3-27 運(yùn)行結(jié)果

在運(yùn)算符重載的使用過(guò)程中,應(yīng)注意以下情況。

(1)并非所有運(yùn)算符都能被重載,不能被重載的運(yùn)算符包括“=”、“? :”、“->”、“new”、“is”、“sizeof”和“typeof”。

(2)重載運(yùn)算符不能改變?cè)瓉?lái)運(yùn)算符的優(yōu)先級(jí)和操作數(shù)。

(3)比較運(yùn)算符必須成對(duì)重載,如“==”和“! =”, “>”和“<”等。

(4)重載運(yùn)算符可由派生類繼承。

3.5 接口

接口是面向?qū)ο笾械挠忠粋€(gè)重要概念,它用于定義類或結(jié)構(gòu)的行為特征。接口包含事件、方法、屬性和索引器4種成員,它只包含這些成員的簽名而不包含實(shí)現(xiàn),這一點(diǎn)和抽象類比較相似;而且接口不能包含字段,且它的所有成員都必須是公開的。

3.5.1 接口的聲明

接口的聲明需要采用interface關(guān)鍵字,如下所示。

        interface MyInterface
        {
            void MyMethod();
            string MyProperty
            {
              get;
            }
        }

在接口MyInterface中,定義了一個(gè)方法成員和一個(gè)屬性。細(xì)心的讀者可能會(huì)發(fā)現(xiàn)以上定義中,接口成員沒(méi)有采用修飾符,如果試圖添加任何修飾符,均會(huì)出現(xiàn)“修飾符無(wú)效”的錯(cuò)誤。因?yàn)樵诮涌诘亩x中規(guī)定了所有接口成員必須是公開的。

3.5.2 接口的使用

前面提到,接口只能包含成員的簽名,不能包含成員的實(shí)現(xiàn)。接口成員必須要在繼承該接口中的類中才能實(shí)現(xiàn)。下面對(duì)MyInterface接口中的MyMethod()方法進(jìn)行實(shí)現(xiàn),代碼如下所示。

        class Program:Interface1
        {
            public void MyMethod()
            {
              Console.WriteLine("實(shí)現(xiàn)了該接口的方法!");
            }
            static void Main(string[] args)
            {
              Program pg = new Program();
              pg.MyMethod();
              Console.ReadKey();
            }
        }

運(yùn)行結(jié)果,如圖3-28所示。

圖3-28 運(yùn)行結(jié)果

上面代碼中,實(shí)現(xiàn)了接口MyInterface中的MyMethod()方法并完成輸出。在使用接口時(shí),應(yīng)注意以下問(wèn)題。

(1)接口自身不能被實(shí)例化,需要在繼承它的類中才能使用。

(2)接口不能包含字段。

(3)接口不能包含靜態(tài)成員。

(4)接口成員默認(rèn)是public類型的,不能在接口成員前面加任何修飾符。

(5)類和結(jié)構(gòu)可以從多個(gè)接口繼承。

(6)接口本身也可以從其他接口繼承,它的繼承機(jī)制和類的繼承機(jī)制一樣。

3.6 面向?qū)ο蟮钠渌黝}

本章前面部分以類為重點(diǎn)介紹了面向?qū)ο蟮南嚓P(guān)知識(shí),但僅有類是不夠的,面向?qū)ο筮€有一些其他主題,比如命名空間等。在本節(jié)中,將對(duì)面向?qū)ο笾衅渌恍┲黝}進(jìn)行介紹,以幫助讀者更好地理解面向?qū)ο蟮谋举|(zhì)。

3.6.1 命名空間

在.NET Framework中,一個(gè)命名空間就是一個(gè)邏輯的命名系統(tǒng),它用于指定一個(gè)范圍,并在該范圍組織代碼(包括類、接口、結(jié)構(gòu)體和枚舉等)。命名空間在前面的代碼中已經(jīng)多次用到,如果需要使用包含在命名空間中的類,則需要使用using指令包含該命名空間,如下所示。

        using System;
        ……
        Console.WriteLine("命名空間的用法!");

System是命名空間,Console是該命名空間中的一個(gè)類。因?yàn)榘薙ystem命名空間,所以才能使用它里面的類。同樣,也可以用如下方式訪問(wèn)Console類,如下所示。

        System.Console.WriteLine("命名空間的用法!");

這里直接使用了顯示的命名空間前綴來(lái)完成Console類的訪問(wèn)。這是一種不推崇的方法,因?yàn)樗鼤?huì)增加代碼的復(fù)雜性。命名空間前面不能加任何修飾符,它的關(guān)鍵字是namespace。在命名空間的內(nèi)部,也可以包含命名空間,稱為命名空間的嵌套,如下所示。

        namespace NameSpaceA
        {
            namespace NameSpaceB
            {
              class Program
              {
              }
            }
        }

NameSpaceB嵌套在NameSpaceA命名空間中,下面為等效代碼。

        namespace NameSpaceA.NameSpaceB
        {
            class Program
            {
            }
        }

如果一個(gè)命名空間的名字很長(zhǎng),但又必須要使用多次,.NET Framwork中提供了一種命名空間別名的方式來(lái)簡(jiǎn)化。如下所示。

        using ns=NameSpaceName;

在需要使用該命名空間的地方,可以直接用ns代替。為了幫助讀者能更好地理解命名空間的用法,下面給出一個(gè)完整的例子進(jìn)行說(shuō)明,代碼如下所示。

        using nsp = NameSpaceA.NameSpaceB.NameSpaceC;              //使用命名空間別名
        //定義嵌套命名空間
        namespace NameSpaceA
        {
            namespace NameSpaceB
            {
              namespace NameSpaceC
              {
                  public class cs
                  {
                      public void output()
                      {
                          Console.WriteLine("命名空間的學(xué)習(xí)!");
                      }
                  }
              }
            }
        }
        //調(diào)用嵌套命名空間中的類成員
        namespace ns
        {
            class Program
            {
              static void Main(string[] args)
              {
                  nsp.cs c = new nsp.cs();
                  c.output();
                  Console.ReadKey();
              }
            }
        }

上面的代碼主要實(shí)現(xiàn)了命名空間的嵌套,命名空間的別名及使用命名空間中包含的類成員,運(yùn)行結(jié)果如圖3-29所示。

圖3-29 運(yùn)行結(jié)果

3.6.2 程序集

程序集是.NET Framework應(yīng)用程序的基本構(gòu)造塊,當(dāng)生成C#應(yīng)用程序時(shí),VS會(huì)在當(dāng)前工程的Debug目錄下生成可移植可執(zhí)行的文件,通常是.exe或.dll文件。在較大的項(xiàng)目中,程序集的作用是十分明顯的。項(xiàng)目經(jīng)理可以把項(xiàng)目劃分成幾個(gè)單獨(dú)的模塊,由不同的人員進(jìn)行開發(fā),然各自生成程序集,最后通過(guò)一定的方式將這些程序集組合起來(lái)即可。

程序集具有以下特點(diǎn)。

(1)程序集以.exe或.dll格式的文件存在。

(2)能在多個(gè)應(yīng)用程序之間實(shí)現(xiàn)程序集的共享。

(3)在單個(gè)應(yīng)用程序中可以使用程序集的兩個(gè)版本。

3.6.3 類庫(kù)

在.NET Framework中,類庫(kù)是由命名空間組成,同時(shí)又是類、接口和值類型組成的庫(kù),這些庫(kù)能對(duì)系統(tǒng)功能進(jìn)行訪問(wèn),是建立.NET Framework應(yīng)用程序、組件和控件的基礎(chǔ)。.NET Framework中包含了大量的系統(tǒng)類庫(kù)供用戶使用,調(diào)用這些類庫(kù)時(shí),系統(tǒng)會(huì)自動(dòng)添加,只需用using指令包含類庫(kù)提供的命名空間即可,比如前面經(jīng)常使用的System命名空間。

但系統(tǒng)提供的類庫(kù)有時(shí)候并不能完全滿足用戶的要求,此時(shí)就需要自定義類庫(kù)。下面通過(guò)例子說(shuō)明類庫(kù)的編寫和調(diào)用。

打開VS2008,在D:\C#\ch3目錄下建立名為ClassLibraryTest的類庫(kù)程序。打開工程,添加如下代碼。

        namespace ClassLibraryTest
        {
            public class Test
            {
              public int Add(int x, int y)
              {
                  return x + y;
              }
              public int Dec(int x, int y)
              {
                  return x - y;
              }
              public int mul(int x, int y)
              {
                  return x * y;
              }
              public int dev(int x, int y)
              {
                  return x / y;
              }
            }
        }

在ClassLibraryTest命名空間的Test類中定義了4個(gè)方法,分別用于計(jì)算兩個(gè)整數(shù)加、減、乘和除的結(jié)果。選擇“生成”—“生成解決方案”命令,或者按F6鍵將以上代碼生成類庫(kù)。此時(shí)轉(zhuǎn)到當(dāng)前工程的Debug目錄下,可以看到名為ClassLibraryTest.dll的動(dòng)態(tài)鏈接庫(kù)文件。下面需要做的工作是調(diào)用該類庫(kù),主要分為以下幾個(gè)步驟。

(1)打開VS2008,在D:\C#\ch3目錄下建立名為ClTest的控制臺(tái)應(yīng)用程序,打開工程,首先需要對(duì)該類庫(kù)進(jìn)行引用。選擇“項(xiàng)目”—“添加引用”—“瀏覽”標(biāo)簽,轉(zhuǎn)到該類庫(kù)工程的Debug目錄,如圖3-30所示。

圖3-30 添加引用

(2)轉(zhuǎn)到“解決方案資源管理器”界面上,可以看到該類庫(kù)已經(jīng)被添加,如圖3-31所示。

圖3-31 添加類庫(kù)

(3)需要包含該類庫(kù)中的命名空間,如下所示。

        using ClassLibraryTest;

(4)在當(dāng)前工程中添加如下代碼。

        namespace Cltest
        {
            class Program
            {
              static void Main(string[] args)
              {
                  Test ts = new Test();
                  Console.WriteLine("兩個(gè)數(shù)相加的結(jié)果為:" + ts.Add(6, 3));
                  Console.WriteLine("兩個(gè)數(shù)相減的結(jié)果為:" + ts.Dec(6, 3));
                  Console.WriteLine("兩個(gè)數(shù)相乘的結(jié)果為:" + ts.mul(6, 3));
                  Console.WriteLine("兩個(gè)數(shù)相除的結(jié)果為:" + ts.dev(6, 3));
                  Console.ReadKey();
              }
            }
        }

(5)運(yùn)行程序,結(jié)果如圖3-32所示。

圖3-32 運(yùn)行結(jié)果

3.7 小結(jié)

本章主要介紹了面向?qū)ο蠹夹g(shù)的基本內(nèi)容。首先是類的相關(guān)知識(shí)的介紹,類是面向?qū)ο蠹夹g(shù)中最基礎(chǔ)也是最重要的內(nèi)容,本章分別從類的定義、類的訪問(wèn)權(quán)限和類的成員等方面對(duì)類的用法進(jìn)行了說(shuō)明。其中采用public、private、protected和abstract等修飾符設(shè)置了類的不同訪問(wèn)權(quán)限;類的成員包括常量、字段、屬性、索引器、方法和事件等,本章通過(guò)例子對(duì)以上成員進(jìn)行了詳細(xì)的說(shuō)明。接下來(lái)介紹了面向?qū)ο蟮娜筇卣鳌^承、多態(tài)和封裝,它們是面向?qū)ο蠹夹g(shù)的核心部分。在有關(guān)接口的內(nèi)容中簡(jiǎn)單介紹了接口的聲明和使用。最后介紹了面向?qū)ο蠹夹g(shù)中的其他一些主題,包括命名空間、程序集和類庫(kù)等。

主站蜘蛛池模板: 三台县| 筠连县| 南城县| 巴中市| 察雅县| 南汇区| 阳江市| 曲水县| 阜康市| 屯留县| 沾化县| 普宁市| 莫力| 南和县| 达拉特旗| 南丰县| 新邵县| 大悟县| 嘉禾县| 松阳县| 巢湖市| 宝兴县| 阜南县| 忻州市| 汕尾市| 进贤县| 深州市| 文昌市| 鸡西市| 蒲城县| 高青县| 新宾| 衢州市| 新龙县| 虎林市| 南阳市| 宜阳县| 洪雅县| 土默特右旗| 疏勒县| 石城县|