2017年9月6日 星期三

.NET C# 類別 class 的宣告與封裝和使用練習

在 C# 中,類別是使用 Class 關鍵字來進行定義。

了解更多關於 [類別
了解更多關於 [類別與物件
了解更多關於 [C# 程式設計手冊 

我們在這裡會進行類別的成員宣告與定義,其中最常用的就是 欄位屬性建構函式方法 的宣告。
在這個類別筆記中,我們定義了底下的類別
在這個類別中,我們定義了一個完整屬性 X 的宣告,你可以使用程式碼片段 propfull 來快速產生這個定義程式碼,這裡表示了屬性 X 的實際儲存內容,將會儲存在欄位 _X 內,當您要進行讀取/寫入動作的時候,是透過了 get存取子和set存取子 這兩個方法來間接存取欄位 _X。
另外,我們使用程式碼片段 prop 這個程式碼片段,宣告了一個自動建置的屬性 Y,在這樣的用法中,我們並不需要額外的定義一個欄位 _Y ,因為,編譯器會幫我們自動產生這些程式碼。使用了自動建置的屬性,大幅簡化了我們在屬性上的程式碼撰寫,也讓我們的程式碼更加的清爽,最重要的是,這兩種做法的最終效果,都是一樣的。
在這個類別中,我們定義了一個建構函式,這個建構函式需要提供兩個參數。若我們在類別中沒有定義任何建構函式,編譯器會自動幫我們產生一個預設建構函式(也就是沒有任何參數)。不過,若我們在類別中有建立了任何建構函式,則,當我們要使用預設建構函式的時候,我們是需要自行定義出這個預設建構函式,否則,我們是無法使用預設建構函式的。
建構函式是我們建立一個類別的執行個體,也就是物件,必須要呼叫的;我們透過了建構函式,可以在其裡面針對這個類別的各個資料進行初始化的動作,設定這些資料的預設值。
最後,我們學習如何在類別中產生這個類別應該提供的行為,也就是方法。Length() 這個方法我們使用了 private 存取修飾詞,宣告這個函式僅能夠在類別內來呼叫,我們會在類別內的 Print()來呼叫,而 Print() 方法的存取修飾詞為 public,這表示,任何程式碼皆可以透過執行個體來執行這個方法。
    public class MyPoint
    {
        #region 座標點 (使用 region 來做到程式碼區隔)
        // 可以使用程式碼片段 propfull
        private double _X;

        public double X
        {
            get { return _X; }
            set { _X = value; }
        }

        // 可以使用程式碼片段 prop
        public double Y { get; set; }
        #endregion

        // 可以使用程式碼片段 ctor
        public MyPoint(double x, double y)
        {
            X = x;
            Y = y;
        }

        /// <summary>
        /// 計算座標點長度
        /// (使用 XML 註解,提升程式碼閱讀性)
        /// 這個方法僅限類別內可以使用
        /// </summary>
        /// <returns></returns>
        private double Length()
        {
            return Math.Sqrt(X * X + Y * Y);
        }

        /// <summary>
        /// 顯示座標詳細資訊
        /// 任何程式碼都可以存取這個方法
        /// </summary>
        /// <returns></returns>
        public string Print()
        {
            return $"({X}, {Y}) 的長度是 {Length()}";
        }
    }

使用類別產生物件,進而存取類別內的資料與行為

首先,您無法使用這個程式碼 MyPoint fooObject1 = new MyPoint(); 來產生一個類別 MyPoint 的執行個體。
您只能夠透過建構函式 MyPoint(double x, double y) 與 new 運算子來建立一個物件。
這個程式碼 MyPoint fooObject4; 表示宣告一個物件變數 fooObject4;而這個物件變數並沒有指向任何參考物件,因此,這個變數物件的參考值為 null,也就是沒有任何內容。
在底下的測試程式碼中,最為重要的觀念就是,
fooObject4 = fooObject2;
這表示了 fooObject4 與 fooObject2; 這兩個物件同時指向了一個相同的物件,而不是產生一個新的物件執行個體,並且讓 fooObject4 物件變數指向這個物件。


不過,若 MyPoint 若是一個結構,則剛剛的設定行為,就會產生另外一個意義。
        static void Main(string[] args)
        {
            // 宣告一個 MyPoint 類別的物件變數,並且指向新產生的 MyPoint 物件
            //MyPoint fooObject1 = new MyPoint();  // 這樣為什麼會發生錯誤

            // 宣告一個 MyPoint 類別的物件變數,並且指向新產生的 MyPoint 物件
            MyPoint fooObject2 = new MyPoint(5, 4);
            // 宣告一個 MyPoint 類別的物件變數,並且指向新產生的 MyPoint 物件
            var fooObject3 = new MyPoint(5, 4);
            // 宣告一個 MyPoint 類別的物件變數
            MyPoint fooObject4;
            // 將物件變數的參考值指向另外一個 MyPoint 物件
            fooObject4 = fooObject2;

            // 在這裡,你可以呼叫 Length() 方法嗎?
            Console.WriteLine($"X:{fooObject2.X}, Y:{fooObject2.Y} / 更多詳細資訊 {fooObject2.Print()}");
            Console.WriteLine($"X:{fooObject3.X}, Y:{fooObject3.Y} / 更多詳細資訊 {fooObject3.Print()}");
            Console.WriteLine($"X:{fooObject4.X}, Y:{fooObject4.Y} / 更多詳細資訊 {fooObject4.Print()}");
            Console.WriteLine("Press any key for continuing...");
            Console.ReadKey();

            Console.WriteLine("修改物件的內容");
            fooObject2.X = 7.0;
            fooObject3.X = 8.0;
            fooObject4.X = 9.0;
            Console.WriteLine($"X:{fooObject2.X}, Y:{fooObject2.Y} / 更多詳細資訊 {fooObject2.Print()}");
            Console.WriteLine($"X:{fooObject3.X}, Y:{fooObject3.Y} / 更多詳細資訊 {fooObject3.Print()}");
            Console.WriteLine($"X:{fooObject4.X}, Y:{fooObject4.Y} / 更多詳細資訊 {fooObject4.Print()}");
            Console.WriteLine("Press any key for continuing...");
            Console.ReadKey();
        }


了解更多關於 [類別
了解更多關於 [類別與物件
了解更多關於 [C# 程式設計手冊 



沒有留言:

張貼留言