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
}