浅学C#(12)——实例构造函数、静态构造函数、析构函数

版权声明:转载请注明出处 https://blog.csdn.net/le_17_4_6/article/details/86607349
实例构造函数
[构造函数修饰符]  标识符([参数列表] )
[ : base ( [参数列表] ) ] [ : this ( [参数列表] ) ]
   {
        构造函数语句块
   }
  • 构造函数修饰符有public、protected、internal、private
  • 构造函数可以重载
  • :base表示调用直接基类中的实例构造函数
  • :this调用该类本身所声明的其他构造函数

  • 构造函数语句块既可以对静态字段赋值,也可以对非静态字段进行初始化
  • 实例构造函数不能被继承
  • 如果一个类中没有声明任何实例构造函数,则系统会提供一个默认的实例构造函数
  • 一旦类中提供了自定义的构造函数,系统则不提供默认构造函数
  • 如果变量是方法的局部变量或者是方法的out参数,编译器就会认为在使用该变量前,代码必须给它显式地设置一个值
  • 对于其他情况(包括类的实例和静态成员字段),编译器会在创建变量时,把变量初始化为默认值

  • 当创建派生类对象时
    • 调用成员对象的构造函数
    • 调用基类构造函数
    • 执行派生类的构造函数
  • 默认情况下执行基类的无参构造函数
  • 如果要执行基类的有参构造函数,则必须在派生类构造函数的基类列表中指出
    字段初始化
using System;
using System.Collections.Generic;
using System.Text;

namespace FieldInitialize
{
    public class A
    {
        private static int InitX()
        {
            Console.WriteLine("A.InitX()");
            return 1;
        }
        private static int InitY()
        {
            Console.WriteLine("A.InitY()");
            return 2;
        }
        private static int InitA()
        {
            Console.WriteLine("A.InitA()");
            return 3;
        }
        private static int InitB()
        {
            Console.WriteLine("A.InitB()");
            return 4;
        }
        private int y = InitY();
        private int x = InitX();
        private static int a = InitA();
        private static int b = InitB();
    }   
    
    class Program
    {
        static void Main(string[] args)
        {
            A a = new A();
            Console.ReadLine();
        }
    }
}

先初始化字段,再调用父类构造函数

using System;
namespace ConstructorExp
{
    class Base
    {
        public Base(int x)
        {
            Console.WriteLine("Base.Base(int)");//4
            this.x = x;
        }
        private static int InitX()
        {
            Console.WriteLine("Base.InitX()"); //3
            return 1;
        }
        public int x = InitX();
    }
    class Derived : Base
    {
        public Derived(int a)
            : base(a)
        {
            Console.WriteLine("Derived.Derived(int)"); //5
            this.a = a;
        }
        public Derived(int a, int b)
            : this(a)
        {
            Console.WriteLine("Derived.Derived(int,int)"); //6        
            this.b = b;
        }
        private static int InitA()
        {
            Console.WriteLine("Derived.InitA()");//1
            return 3;
        }
        private static int InitB()
        {
            Console.WriteLine("Derived.InitB()");//2
            return 4;
        }
        public int a = InitA();
        public int b = InitB();
    }    
    class Program
    {
        static void Main(string[] args)
        {
            Derived b = new Derived(1, 2);
            Console.ReadLine();
        }
    }
}
静态构造函数
  • 静态构造函数修饰符:static
  • 静态构造函数仅对静态数据成员进行初始化,不能对非静态数据成员进行初始化
  • 静态构造函数都是私有的
  • 静态构造函数是不可继承的,而且不能被直接调用
  • 如果类中没有声明静态构造函数,而又包含带有初始设定的静态字段,那么编译器会自动生成一个默认的静态构造函数
using System;
class A
{
    protected static int x;
    protected int y;
    static A()
    {
        x = 10; //1
    }
    public A(int a,int b) //3
    {
        x = a;
        y = b;
    }
    public void print()
    {
        Console.WriteLine("x={0},y={1}", x, y);
    }
}
class B : A
{
    protected new static int x;
    private int z;
    public B(int a,int b,int c):base(a,b)
    {
        z = c; //4
    }
    static B()
    {
        x = 20; //2
    }
    new public void print()
    {
        Console.WriteLine("x={0},y={1},z={2}", x, y, z);
    }
}
class Test
{
    static void Main()
    {
        A objA = new B(3, 4, 5);
        objA.print();
        B objB = (B)objA;
        objB.print();
    }
}
析构函数
  • 析构函数不能被重载,不能被继承
  • 一个类如果没有显式声明析构函数,则编译器将自动产生一个默认的析构函数
  • 析构函数不能由程序显式调用,由系统在释放对象时调用
  • 析构函数是在“垃圾回收器”回收对象的存储空间之前调用的,最终会调用System.Object的Finalize( )
  • 可使用System.GC.Collect()请求运行垃圾回收器,例如代 码中有大量的对象刚刚停止使用
  • 析构函数在C#中充当鸡肋的角色,由于有垃圾 收集器清理资源,所以不能预计它们会在什么时候运行

  • Finalize方法调用时刻是不确定的
  • 如果对对象执行了finalize()方法,在对该对象进行无用单元收集时,会对性能产生重大影响。
    所以在一般情况下,最好不要执行该方法
  • 常见场合是在对象维护不由.NET管理的资源时,例如文件或数据库连接,需要执行finalize断开这些连接

  • Dispose()和Close()方法优点是资源在不需要时立即被释放,对于像独占文件锁那样的对象来说是非常好的
  • Close( )主要用于指定资源可能以后会再次打 开,而Dispose( )是一种最终处理,调用Dispose( )意味着客户机代码最终会删除这个对象
  • 如关闭一个文件或数据库连接使用Close()释放各种GDI或其他Windows对象的句柄使用 Dispose()
  • IDisposable C#提供using语法确保在引用出作用域时,在 对象上自动调用Dispose( )
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace DestructorExp1
{
    public class Article : System.IDisposable
    {
        public int m_Price;
        public Article(int price) { this.m_Price = price; }
        public void Dispose()
        {
            Console.WriteLine("m_Price=" + m_Price);
         }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Article a = new Article(300);
            Article b = new Article(400);
            using (a) using(b)
            {

            }
            Console.ReadLine();
        }
    }
}

必须实现IDisposable接口,才能使用using语法

Class  ResourceGobbler: IDisposable
{
        ……
      public  void  Dispose( )
   { 
        ……
   }
}

什么情况下需要自己写析构函数?
使用析构函数主要是为了释放资源。

  • 如:当该类中打开了一个文件,对象销毁时,应当关闭这个文件。
  • 又如:当该类中打开了数据库,对象销毁时,应当关闭这个连接。
  • 再如:当该类中申请了大量内存,对象销毁时,应当释放这些内存。

调用析构函数的时机由.NET的垃圾回收器来决定

猜你喜欢

转载自blog.csdn.net/le_17_4_6/article/details/86607349