跳轉至內容

C# 程式設計/物件

來自華夏公益教科書

.NET 框架包含多種語言,這些語言都遵循面向物件程式設計 (OOP) 的軟體開發方法。該標準定義了所有物件都支援

  • 繼承 - 繼承和擴充套件現有功能的能力。
  • 封裝 - 允許使用者僅看到特定部分,並以特定方式與之互動的能力。
  • 多型性 - 物件可以動態分配,但對可以對物件執行的操作有一些可預測性的能力。

物件與現實世界中的物件是同義詞。想想任何物體,想想它是什麼樣子的,它如何測量和互動。在建立 OOP 語言時,推理是,如果它模擬人類的思維過程,它將簡化編碼體驗。

例如,讓我們考慮一把椅子,它的尺寸、重量、顏色和它是由什麼製成的。在 .NET 中,這些值稱為“屬性”。這些是定義物件狀態的值。請注意,有兩種方法可以公開值:欄位和屬性。建議的方法是公開屬性而不是欄位。

因此,我們對物件的概念有了一個現實世界的想法。在計算機傳遞資訊方面的實用性方面,在程式中傳遞物件會消耗大量資源。想想一輛汽車,它有多少屬性——數百個、數千個。計算機一直傳遞這些資訊會浪費記憶體、處理時間,因此使用它是一個壞主意。因此,物件有兩種形式

  • 引用型別
  • 值型別

引用型別和值型別

[編輯 | 編輯原始碼]

引用型別就像指向值的指標。把它想象成一張寫著街道地址的紙,地址通向你的房子——你的有數百個屬性的物件。如果你想找到它,去地址說的地方!這正是計算機內部發生的情況。引用儲存為一個數字,對應於物件存在的記憶體中的某個地方。因此,您不必四處移動物件——就像每次想要檢視它時都建造一座複製品一樣——您只需檢視原始物件。

值型別是確切的值本身。值非常適合儲存少量資訊:數字、日期等。

它們在處理方式上有所不同,因此我們將稍後在本文中進行介紹。

除了查詢值之外,我們還需要一種與物件互動的方式,以便可以執行某些操作。想想檔案——瞭解檔案的長度很好,但是如何進行 Read() 操作呢?因此,我們可以使用稱為*方法*的東西來對物件執行操作。

一個例子是矩形。矩形的屬性是

  • 長度
  • 寬度

“函式”(或 .NET 中的*方法*)將是

  • Area (= Length*Width)
  • Perimeter (= 2*Length + 2*Width)

方法不同於屬性,因為它們需要對資料進行一些轉換才能獲得結果。方法可以返回結果(例如 Area),也可以不返回結果。就像上面的椅子一樣,如果你 Sit() 在椅子上,沒有預期的反應,椅子只是……起作用了!

System.Object

[編輯 | 編輯原始碼]

為了支援 OOP 的第一個規則——繼承,我們定義了所有物件都將從中派生的東西——這就是 System.Object,也稱為 Objectobject。此物件定義了一些所有物件都可以使用的方法(如果需要)。這些方法包括

  • GetHashCode() - 獲取該物件唯一的數字。
  • GetType() - 獲取有關物件的資訊,例如方法名稱、物件名稱等。
  • ToString() - 將物件轉換為文字表示形式 - 通常用於輸出到螢幕或檔案。

由於所有物件都從此類派生(無論您是否定義它),因此任何類都將具有這三種方法,可以隨時使用。由於我們總是從 System.Object 或本身從 System.Object 派生的類繼承,因此我們增強和/或擴充套件了它的功能。就像在現實世界中,人類、貓、狗、鳥、魚都是“生物”的改進和專門版本。

物件基礎

[編輯 | 編輯原始碼]

預設情況下,所有物件都是引用型別。為了支援值型別,物件必須從 System.ValueType 抽象類而不是 System.Object 繼承。

建構函式

[編輯 | 編輯原始碼]

當建立物件時,它們會透過“建構函式”進行初始化。建構函式設定物件,準備使用。因為物件需要在使用之前建立,所以建構函式是隱式建立的,除非開發人員對其進行了不同的定義。建構函式有 3 種類型

  • 複製建構函式
  • 靜態建構函式
  • 預設建構函式 - 不接受引數。
  • 過載建構函式 - 接受引數。

過載建構函式會自動刪除隱式預設建構函式,因此開發人員必須顯式定義預設建構函式,如果他們想使用它。

建構函式是 C# 中的一種特殊方法,允許物件在建立時初始化自身。如果使用建構函式方法,則無需編寫單獨的方法來將初始值分配給物件的成員變數。

建構函式方法的重要特徵

  1. 建構函式方法與類本身的名稱相同。
  2. 建構函式方法通常宣告為 public。
  3. 建構函式方法宣告為 public,因為它用於從宣告它的類外部建立物件。我們也可以將建構函式方法宣告為 private,但這樣建構函式就無法用於建立物件。
  4. 建構函式方法沒有返回型別(甚至沒有 void)。
  5. C# 為每個類提供一個預設建構函式。此預設建構函式將成員變數初始化為零。但是,如果我們編寫自己的建構函式方法,則不會使用預設建構函式。
  6. 建構函式方法用於將初始值分配給成員變數。
  7. 當建立物件時,建構函式由 new 關鍵字呼叫。
  8. 我們可以在一個類中定義多個建構函式。這被稱為建構函式過載。所有建構函式方法的名稱相同,但它們的簽名不同,即引數的數量和型別不同。
  9. 如果聲明瞭建構函式,則不會生成預設建構函式。

複製建構函式

[編輯 | 編輯原始碼]

複製建構函式透過複製另一個物件中的變數來建立物件。複製建構函式是透過建立所需型別的物件並傳遞要複製的物件來呼叫的。

在以下示例中,我們將一個 Rectangle 物件傳遞給 Rectangle 建構函式,以便新物件與舊物件具有相同的值。

using System;

namespace CopyConstructor
{
    class Rectangle
    {
        public int length;
        public int breadth;

        public Rectangle(int x, int y)         // constructor fn
        {
            length = x;
            breadth = y;
        }

        public Rectangle(Rectangle r)
        {
            length = r.length;
            breadth = r.breadth;
        }

        public void display()
        {
            Console.WriteLine("Length = " + length);
            Console.WriteLine("Breadth = " + breadth);
        }
    }   // end of class Rectangle

    class Program
    {
        public static void Main()
        {
            Rectangle r1 = new Rectangle(5, 10);
            Console.WriteLine("Values of first object");
            r1.display();

            Rectangle r2 = new Rectangle(r1);
            Console.WriteLine("Values of second object");
            r2.display();

            Console.ReadLine();
        }
    }
}

靜態建構函式

[編輯 | 編輯原始碼]

靜態建構函式在執行時首次訪問類時首次呼叫。靜態變數始終可訪問,因此執行時必須在其首次訪問時對其進行初始化。下面的示例在偵錯程式中逐步執行時,將顯示 static MyClass() 僅在訪問 MyClass.Number 變數時訪問。

C# 支援兩種型別的建構函式:靜態建構函式和例項建構函式。例項建構函式在每次建立該類的物件時都會被呼叫,而靜態建構函式僅被呼叫一次。靜態建構函式在建立類的任何物件之前被呼叫,通常用於初始化類的任何靜態資料成員。

靜態建構函式是透過在建構函式定義中使用關鍵字 static 來宣告的。此建構函式不能有任何引數或訪問修飾符。此外,類只能有一個靜態建構函式。例如

using System;
using System.Collections.Generic;
using System.Text;

namespace StaticConstructors
{
    class Program
    {
        static void Main(string[] args)
        {
            int i = 0;
            int j = 0;
            Console.WriteLine("Static Number = " + MyClass.Number);
        }
    }

    class MyClass
    {
        private static int _number;
        public static int Number { get { return _number; } }
        static MyClass()
        {
            Random r = new Random();
            _number = r.Next();
        }
    }
}

預設建構函式

[編輯 | 編輯原始碼]

預設建構函式不接受任何引數,並且如果不存在其他建構函式,則隱式定義。下面的程式碼示例顯示了建立類之前的結果和之後的結果。

// Created by the developer
class MyClass
{
}

// Created by the compiler
class MyClass : System.Object
{
     public MyClass() : base()
     {
     }
}

過載建構函式

[編輯 | 編輯原始碼]

為了以各種形式初始化物件,建構函式允許透過傳遞引數來定製物件。

 class MyClass
    {
        private int _number;
        public int Number { get { return _number; } }
        
        public MyClass()
        {
            Random randomNumber = new Random();
            _number = randomNumber.Next();
        }
  
        public MyClass(int seed)
        {
            Random randomNumber = new Random(seed);
            _number = randomNumber.Next();
        }
   }

呼叫其他建構函式

[編輯 | 編輯原始碼]

為了最小化程式碼,如果另一個建構函式實現了更好的功能,您可以指示建構函式呼叫過載(或預設)建構函式並使用特定引數。

 class MyClass
    {
        private int _number;
        public int Number { get { return _number; } }
        
        public MyClass() : 
             this ( DateTime.Now.Milliseconds ) // Call the other constructor passing in a value.
        {
            
        }
  
        public MyClass(int seed)
        {
            Random r = new Random(seed);
            _number = r.Next();
        }
   }

也可以呼叫基類的建構函式,而不是當前例項中的建構函式。

 class MyException : Exception
    {
        private int _number;
        public int Number { get { return _number; } }
        
        public MyException ( int errorNumber, string message, Exception innerException)
                 : base( message, innerException )
        {
             _number = errorNumber;
        }
   }

解構函式

[編輯 | 編輯原始碼]

除了“構造”之外,物件還可以透過垃圾收集器清除時執行清理操作。與建構函式一樣,解構函式也使用與類相同的名稱,但前面帶有波浪號 (~) 符號。但是,垃圾收集器僅在直接呼叫或有理由回收記憶體時才執行,因此解構函式可能很長時間沒有機會清理資源。在這種情況下,請檢視 Dispose() 方法(來自 IDisposable 介面)的使用。

解構函式透過在建構函式前面使用 ~ 符號來識別,該建構函式沒有訪問修飾符。例如

 class MyException : Exception
    {
        private int _number;
        public int Number { get { return _number; } }
        
        public MyException ( int errorNumber, string message, Exception innerException)
                : base( message, innerException )
        {
             _number = errorNumber;
        }

        ~MyException()
        {
        }
   }


華夏公益教科書