C Sharp/Classes

維基教科書,自由的教學讀本

C#是純粹的物件導向語言。所有代碼都包含在類中。

類的實例可以用關鍵字new後跟隨類的名字來創建。C#沒有delete,其託管資源不需要delete,也不能顯式delete,完全由.net的垃圾回收器來管理。

例子1[編輯]

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開始,允許可選參數與默認值,例如:

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

構造函數[編輯]

例如:

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#有垃圾收集設施,因此幾乎不用終接器(finalizers)。非託管資源,比如打開的文件句柄,創建的位圖句柄等,應該實現IDisposable接口和析構函數,並且在析構函數中釋放資源作為最後的補救手段。Dispose的方法用於提前顯式釋放掉非託管資源,再加上一行代碼GC.SuppressFinalize(this)告訴.net的垃圾回收器,不需要再調用一次析構函數來釋放非託管資源了。

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!

屬性[編輯]

屬性可以是靜態的或實例的。

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
        }
    }
}

更為簡明的方法:

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();
}


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#索引器(indexers)是類成員,用於數組訪問操作(例如list[0]訪問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#事件是類成員,用於向客戶暴露出通知。事件只能用於觸發(fire),不能用於賦值。

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 a event not have any method and it was fired, it causes a exception!
            //       for all effects when programming with events, assign one private method to event
            //       or simply do a verification before fire 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 fire, the method added to event are called too.
            // note that we cannot use =
            // is only += to add methods to event or -= do retire a 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.
    }
}

結構[編輯]

結構(Structures或structs),類似於類,但有細微差別:

  • 結構的實例是值,類的實例是引用。
  • 結構不能繼承
struct Employee
{
    public int m_iAge;
    private string m_strName;

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

從C# 2.0,從結構內部可以有數組(arrays):

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

這種數組使用指針算術,類似於C語言的不安全訪問。

結構的構造函數[編輯]

結構的構造函數實際上是初始化(內存)函數[1]。所以必須有參數。

結構的賦值操作要求右側的結構實例必須初始化。[2]

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;
    }
}

靜態類[編輯]

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

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

參考文獻[編輯]

  1. Greg Beech(2008年6月16日).Structure constructors.MSDN.於2012年4月12日查閱.原文:「Because structures are simply an inline area of memory, they cannot be null, and so the CLR has to be able to ensure that the area of memory is totally initialized rather than being partly garbage. For this reason, you'll often hear the 'constructors' on structures called (arguably more correctly) 'initializers' because the don't construct an object they just initialize an area of memory.」
  2. John Sharp.Microsoft® Visual C#® 2005 Step by Step / Copying Structure Variables.Google Books.於2012年4月12日查閱.原文:「You're allowed to initialize or assign one struct variable to another struct variable, but only if the struct variable on the right side is completely initalized (that is, if all its fields are initialized).」