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).”