C Sharp/Objects

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

System.Object[編輯]

對象默認繼承自System.Object, 也稱作Objectobject。其方法有:

  • GetHashCode() - 獲取對象的獨一無二Id
  • GetType() -
  • ToString() -

對象[編輯]

對象默認是引用類型。如果想支持值類型,就必須從System.ValueType抽象類派生。

構造函數[編輯]

構造函數通常為public。 構造函數沒有返回類型(即使void也不行)。使用new關鍵字創建一個類的實例時,調用構造函數。

拷貝構造函數[編輯]

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

靜態構造函數[編輯]

當運行時第一次訪問一個類時,該類的靜態構造函數被調用(且僅此一次),給類的靜態數據成員賦值。

靜態構造函數必須無參。只能有一個靜態構造函數。

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方法[編輯]

析構函數直到垃圾回收時才被調用。所以考慮適用Dispose()方法。

資源類型分為:

  • 託管資源:由CLR創建和釋放
  • 非託管資源:資源的創建和釋放不由CLR管理。比如IO、網絡連接、資料庫連接等等。需要開發人員手動釋放。

終結器(Finalizer)是GC允許對象被摧毀前清理非受管的資源的方法。但GC不保證終結器一定會被調用、調用的次序(如一個對象引用另一個對象,這兩個對象的終結器的執行次序)。不能顯式調用或覆蓋終結器,它是編譯器根據析構函數隱式生成,由GC隱式調用。終結器總是protected而非公有或私有。終結器應該只釋放非受管資源(受管資源隨後由GC清理)。不要在終結器中分配內存、調用虛函數、拋出未處理的異常。不要給值類型定義終結器(因為它不會被GC調用)。不要創建空的析構函數。

class Test
{
 // Some Code
 ~Test
 {
    //Necessary cleanup code
 }
}
//将被自动编译为:
protected override void Finalize()
{
    try
    {
      //Necessary cleanup code
    }
    finally
    {
       base.Finalize();
    }
}

類庫會提供釋放的方法,即約定為Dispose,調用即可。有非受管資源需要清理釋放,應該顯式調用Dispose方法。反之,如果一個類有Dispose方法清理受管資源,則程序就應該顯式調用Dispose方法而不應該等待GC調用終結器。這樣的類應該實現IDisposable接口和the Dispose方法。最佳實踐建議同時實現Dispose方法和析構函數,顯式調用Dispose釋放非受管資源,GC調用終結器可處理編程者忽略調用Dispose的情形。如果有析構函數,就應該實現IDisposable。應考慮Dispose被調用多次的可能。對值類型不應寫Dispose方法。Dispose方法中不應該拋出異常。

  public class Base: IDisposable
  {
    private bool isDisposed = false;
    public void Dispose() 
    {
      Dispose(true);
      GC.SuppressFinalize(this); //要求runtime不要再调用这个终结器了。因为重复释放非受管资源会造成不可控后果。
    }
   protected virtual void Dispose(bool disposing) 
   {
     if(!isDisposed)
     {
        if (disposing) 
        {
           // Code to dispose managed resources 
           // held by the class
         }
     }      
     // Code to dispose unmanaged resources 
     // held by the class
     isDisposed = true;
     base.Dispose(disposing);
  }

  ~Base()
   {
      Dispose (false);
   }
}

public class Derived: Base
{   
   protected override void Dispose(bool disposing) 
   {
     if (disposing) 
     {
        // Code to cleanup managed resources held by the class.
      }
     // Code to cleanup unmanaged resources held by the class.
     base.Dispose(disposing);
 }
  // Note that the derived class does not // re-implement IDisposable
}