跳轉至內容

C# 程式設計/類

來自華夏公益教科書,開放的書籍,為一個開放的世界

與其他面向物件程式語言一樣,C# 程式的功能在 中實現。類的 方法屬性 包含定義類行為的程式碼。

C# 類透過將功能 封裝 在屬性和方法中,並透過啟用多種型別的 多型(包括透過 繼承子型別多型 和透過 泛型引數多型)來支援 資訊隱藏

可以定義幾種型別的 C# 類,包括 例項 類(可以例項化的 標準 類)、靜態 類和 結構體

類使用 class 關鍵字定義,後面跟著一個識別符號來命名類。然後可以使用 new 關鍵字後跟類的名稱來建立類的例項。

下面的程式碼定義了一個名為 Employee 的類,它具有 NameAge 屬性,以及空方法 GetPayCheck()Work()。它還定義了一個 Sample 類,該類例項化並使用 Employee

public class Employee
{
    private int _Age;
    private string _Name;

    public int Age
    {
        get { return _Age; }
        set { _Age = value; }
    }

    public string Name
    {
        get { return _Name; }
        set { _Name = value; }
    }

    public void GetPayCheck()
    {
    }

    public void Work()
    {
    }
}

public class Sample
{
    public static void Main()
    {
        Employee marissa = new Employee();

        marissa.Work();
        marissa.GetPayCheck();
    }
}

C# 方法 是包含程式碼的類成員。它們可能具有返回值和 引數 列表,以及 泛型 型別宣告。與欄位一樣,方法可以是 靜態 的(與類相關聯並透過類訪問)或 例項 的(與類的物件例項相關聯並透過該類的物件例項訪問,以及 泛型 型別宣告)。

C# 4.0 開始,方法可以具有具有預設值的可選引數,正如 C++ 使用者已經知道的。例如,方法

void Increment(ref int x, int dx = 1)

可以只用一個引數呼叫,因為第二個引數dx被初始化為預設值。[1]

類的建構函式

[編輯 | 編輯原始碼]

類的 建構函式 控制其初始化。當程式請求類型別的新物件時,建構函式的程式碼執行以初始化類的例項。建構函式通常設定其類的屬性,但它們不限於這樣做。

與其他方法一樣,建構函式可以具有 引數。要使用帶引數的建構函式建立物件,new 命令接受引數。下面的程式碼定義瞭然後例項化了 Employee 類的多個物件,一次使用不帶引數的建構函式,一次使用帶引數的版本

public class Employee
{
    public Employee()
    {
        System.Console.WriteLine("Constructed without parameters");
    }

    public Employee(string strText)
    {
        System.Console.WriteLine(strText);
    }
}

public class Sample
{
    public static void Main()
    {
        System.Console.WriteLine("Start");
        Employee Alfred = new Employee();
        Employee Billy  = new Employee("Parameter for construction");
        System.Console.WriteLine("End");
    }

輸出

Start
Constructed without parameters
Parameter for construction
End

建構函式可以相互呼叫

public class Employee
{
    public Employee(string strText, int iNumber)
    {
        ...
    }
    
    public Employee(string strText)
        : this(strText, 1234) // calls the above constructor with user-specified text and the default number
    { }
    
    public Employee()
        : this("default text") // calls the above constructor with the default text
    { }
}

終結器(解構函式)

[編輯 | 編輯原始碼]

終結器 與建構函式相反,它們定義了物件的最終行為,並在物件不再使用時執行。儘管它們經常在 C++ 中用於釋放物件保留的資源,但由於 .NET Framework 垃圾收集器,它們在 C# 中的使用頻率較低。物件的終結器(不接受任何引數)在物件不再被引用後的一段時間內被呼叫,但垃圾收集的複雜性使得終結器的具體時間不確定。

public class Employee
{
    public Employee(string strText)
    {
        System.Console.WriteLine(strText);
    }

    ~Employee()
    {
        System.Console.WriteLine("Finalized!");
    }

    public static void Main()
    {
        Employee marissa = new Employee("Constructed!");

        marissa = null;
    }
}

輸出

Constructed!
Finalized!

C# 屬性 是類成員,它們使用 欄位 的語法公開方法的功能。它們簡化了呼叫傳統 getset 方法(也稱為 訪問器 方法)的語法。與方法一樣,它們可以是 靜態 的或 例項 的。

屬性以以下方式定義

public class MyClass
{
    private int m_iField = 3; // Sets integerField with a default value of 3

    public int IntegerField
    {
        get
        {
            return m_iField;  // get returns the field you specify when this property is assigned
        }
        set
        {
            m_iField = value; // set assigns the value assigned to the property of the field you specify
        }
    }
}

對於 getter/setter 方法,更簡短的方式是訪問器,它們在一行中完成兩者

class Culture
{
    public int TalkedCountries { get; set; }
    public string Language { get; set; }
}

class InterculturalDialogue
{
    Culture culture;

    culture.Language = "Italian";  // ==> culture.SetLanguage("Italian");

    string strThisLanguage = culture.Language; // ==> ... = culture.GetLanguage();
}

該程式碼等效於 GetLanguage 和 SetLanguage 方法定義,但無需定義這些方法。使用者可以直接訪問成員,當然,如果它不是私有的。

C# 關鍵字 value 包含分配給屬性的值。定義屬性後,可以使用它就像一個變數。如果你要在屬性的 get 和 set 部分編寫一些額外的程式碼,它將像一個方法一樣工作,允許你在讀寫變數之前操作資料。

public class MyProgram
{
    MyClass myClass = new MyClass;

    Console.WriteLine(myClass.IntegerField); // Writes 3 to the command line.
    myClass.IntegerField = 7; // Indirectly assigns 7 to the field myClass.m_iField     
}

以這種方式使用屬性提供了一種乾淨且易於使用的機制來保護資料。

索引器

[編輯 | 編輯原始碼]

C# 索引器 是類成員,它們定義 陣列訪問 操作的行為(例如 list[0] 用於訪問 list 的第一個元素,即使 list 不是陣列)。

要建立索引器,請使用 this 關鍵字,如以下示例所示

public string this[string strKey]
{
    get { return coll[strKey]; }
    set { coll[strKey] = value; }
}

此程式碼將建立一個返回字串值的字串索引器。例如,如果類是 EmployeeCollection,你可以編寫類似以下程式碼

EmployeeCollection e = new EmployeeCollection();
.
.
.
string s = e["Jones"];
e["Smith"] = "xxx";

C# 事件 是類成員,它們向類的客戶端公開通知。事件只觸發,從不賦值。

using System;

// Note: You need to know some about delegate, properties and methods to understand this sample
namespace EventSample
{
    /// <summary>
    /// This delegate defines the signature of the appropriate method
    /// </summary>
    public delegate void ContractHandler(Employee sender);

    /// <summary>
    ///     Employee class
    /// </summary>
    public class Employee
    {
        /// <summary>
        ///     Field for the info whether or not the Employee is engaged
        /// </summary>
        private bool bIsEngaged = false;
        /// <summary>
        ///     Age of the employee
        /// </summary>
        private int iAge = -1;
        /// <summary>
        ///     Name of the employee
        /// </summary>
        private String strName = null;

        /// <summary>
        /// *** The our event *** 
        /// Is a collection of methods that will be called when it fires
        /// </summary>
        public event ContractHandler Engaged;

        /// <summary>
        ///     Standard constructor
        /// </summary>
        public Employee()
        {
            // Here, we are adding a new method with appropriate signature (defined by delegate)
            // note: when an event has no method and it was fired, it causes an exception!
            //       for all effects when programming with events, assign one private method to event
            //       or simply do a verification before firing it! --> if (event != null)
            this.Engaged += new ContractHandler(this.OnEngaged);
        }

        /// <summary>
        ///     Event handler for the "engaged" event
        /// </summary>
        /// <param name="sender">
        ///     Sender object
        /// </param>
        private void OnEngaged(Employee sender)
        {
            Console.WriteLine("private void OnEngaged was called! this employee is engaged now!");
        }

        /// <summary>
        ///     Accessor for the employee name
        /// </summary>
        public string Name
        {
            get
            {
                return strName;
            }

            set
            {
                strName = value;
            }
        }

        /// <summary>
        ///     Accessor for the employee age
        /// </summary>
        public int Age
        {
            get
            {
                return m_iAge;
            }

            set
            {
                m_iAge = value;
            }
        }

        /// <summary>
        ///     Accessor for the information about employee engagement
        /// </summary>
        public bool IsEngaged
        {
            get
            {
                return bIsEngaged;
            }

            set
            {
                if (bIsEngaged == false && value == true)
                {
                    // here we fires event (call all the methods that it have)
                    // all times when IsEngaged is false and set to true;
                    Engaged(this);
                }

                bIsEngaged = value;
            }
        }
    }

    /// <summary>
    ///     Class for the entry point
    /// </summary>
    public class EntryPointClass
    {
        static void Main(string[] a_strArgs)
        {
            Employee simpleEmployee = new Employee();

            simpleEmployee.Age = 18;
            simpleEmployee.Name = "Samanta Rock";
            
            // Here...
            // This is saying when the event fires, the method added to event are called too.
            // note that we cannot use =
            // is only += to add methods to event or -= do retire an event
            simpleEmployee.Engaged += new ContractHandler(SimpleEmployee_Engaged);
        
            // make attention here...
            // when I assign true to this property, 
            // the event Engaged will be called
            // when event is called, all method that it have, are called!
            simpleEmployee.IsEngaged = true;

            Console.ReadLine();

            return;
        }

        /// <summary>
        ///     Event handler for the registered "engaged" event
        /// </summary>
        /// <param name="sender">
        ///     Event sender
        /// </param>
        static void SimpleEmployee_Engaged(Employee sender)
        {
            Console.WriteLine("The employee {0} is happy!", sender.Name);
        }
    }
}

有關詳細資訊,請參閱 此處

運算子過載

[編輯 | 編輯原始碼]

C# operator 定義是類成員,它們定義或重新定義類例項上基本 C# 運算子(隱式或顯式呼叫)的行為

public class Complex
{
    private double m_dReal, m_dImaginary;
    
    public double Real
    {
        get { return m_dReal; }
        set { m_dReal = value; }
    }
    
    public double Imaginary
    {
        get { return m_dImaginary; }
        set { m_dImaginary = value; }
    }
    
    // binary operator overloading
    public static Complex operator +(Complex c1, Complex c2)
    {
        return new Complex() { Real = c1.Real + c2.Real, Imaginary = c1.Imaginary + c2.Imaginary };
    }
    
    // unary operator overloading
    public static Complex operator -(Complex c)
    {
        return new Complex() { Real = -c.Real, Imaginary = -c.Imaginary };
    }
    
    // cast operator overloading (both implicit and explicit)
    public static implicit operator double(Complex c)
    {
        // return the modulus - sqrt(x^2 + y^2)
        return Math.Sqrt(Math.Pow(c.Real, 2) + Math.Pow(c.Imaginary, 2));
    }
    
    public static explicit operator string(Complex c)
    {
        // we should be overloading the ToString() method, but this is just a demonstration
        return c.Real.ToString() + " + " + c.Imaginary.ToString() + "i";
    }
}

public class StaticDemo
{
    public static void Main()
    {
        Complex number1 = new Complex() { Real = 1, Imaginary = 2 };
        Complex number2 = new Complex() { Real = 4, Imaginary = 10 };
        Complex number3 = number1 + number2; // number3 now has Real = 5, Imaginary = 12
        
        number3 = -number3; // number3 now has Real = -5, Imaginary = -12
        double testNumber = number3; // testNumber will be set to the absolute value of number3
        Console.WriteLine((string)number3); // This will print "-5 + -12i".
        // The cast to string was needed because that was an explicit cast operator.
    }
}

結構體

[編輯 | 編輯原始碼]

結構體(或 structs)使用 struct 關鍵字定義,後面跟著一個 識別符號 來命名結構體。它們與類類似,但有一些細微的差別。結構體 用作類的輕量級版本,可以幫助在處理小型資料結構時減少記憶體管理工作。然而,在大多數情況下,使用標準 是更好的選擇。

structclass 的主要區別在於 struct例項,而 class例項引用。 因此,當您按值將 struct 傳遞給函式時,您會獲得物件的副本,因此對它的更改不會反映在原始物件中,因為現在有兩個不同的物件。 但如果您按引用傳遞 class 的例項,那麼只有一個例項。

下面的 Employee 結構聲明瞭一個 public 欄位和一個 private 欄位。 透過 public 屬性 Name 可以訪問 private 欄位。

struct Employee
{
    public int m_iAge;
    private string m_strName;

    public string Name
    {
        get { return m_strName; }
        set { m_strName = value; }
    }
}

從 C# 2.0 開始,可以在結構中包含 陣列,但只能在不安全的上下文中。

struct data
{
    int header;
    fixed int values[10];
}

使用指標運算訪問陣列。 值將以陣列值作為 C 風格陣列使用索引等方式進行處理。

結構建構函式

[edit | edit source]

結構需要建構函式 - 或者更準確地說,是初始化器,因為它們不是構造而是僅僅初始化記憶體 [2] - 以便其內容不會未初始化。 因此,不允許沒有引數的建構函式。

當且僅當賦值右側的結構變數都已初始化時,結構變數才能彼此賦值。 [3]

struct Timestamp
{
    private ushort m_usYear;
    private ushort m_usMonth;
    private ushort m_usDayOfMonth;
    private ushort m_usHour;
    private ushort m_usMinute;
    private ushort m_usSecond;

    public Timestamp(ushort usYear,
        ushort usMonth,
        ushort usDay,
        ushort usHour,
        ushort usMinute,
        ushort usSecond)
    {
        m_usYear = usYear - 1900;
        m_usMonth = usMonth;
        m_usDay = usDay;
        m_usHour = usHour;
        m_usMinute = usMinute;
        m_usSecond = usSecond;
    }
}

靜態類

[edit | edit source]

靜態類 通常用於實現 單例模式static 類的所有方法、屬性和欄位也都是 static(例如 System.Console 類的 WriteLine() 方法),因此可以在不例項化 static 類的情況下使用它們。

public static class Writer
{
    public static void Write()
    {
        System.Console.WriteLine("Text");
    }
}

public class Sample
{
    public static void Main()
    {
        Writer.Write();
    }
}

參考文獻

[edit | edit source]
  1. [[[w:C_Sharp_syntax#Optional_parameters|Optional parameters]] "Optional parameters"]. Retrieved 2018-02-01. {{cite web}}: Check |url= value (help)
  2. Greg Beech (2008-06-16). "Structure constructors". http://social.msdn.microsoft.com/: MSDN. Retrieved 2012-04-12. 因為結構只是記憶體中的一個內聯區域,所以它們不能為 null,所以 CLR 必須能夠確保該記憶體區域完全初始化,而不是部分垃圾。 出於這個原因,您經常會聽到結構的“建構函式”被稱為(可能更準確地說)“初始化器”,因為它們不是構造物件而是僅僅初始化記憶體區域。 {{cite web}}: External link in |location= (help)
  3. John Sharp. "Microsoft® Visual C#® 2005 Step by Step / Copying Structure Variables". http://books.google.at/: Google Books. Retrieved 2012-04-12. 您可以初始化或將一個 struct 變數賦值給另一個 struct 變數,但前提是右側的 struct 變數必須完全初始化(即,如果其所有欄位都已初始化)。 {{cite web}}: External link in |location= (help)

華夏公益教科書