C#构造函数的运用

单件模式(Singleton Pattern)

C#静态构造函数

这段时间开始看看设计模式,刚刚看了下Singleton模式,实现其最简洁的方法是:

     class  Singleton
    
{
        
public static readonly Singleton instance = new Singleton();
        
private Singleton()
        
{ }
    }

很多人对这段代码不大理解,其实等价与:
class  Singleton
    
{
        
public static readonly Singleton instance;
        
static Singleton()
        
{
            instance 
= new Singleton();
        }

        
private Singleton()
        
{ }
    }

  现在都明白了吧,现在我们来探讨下静态构造函数,看看他是怎么来实现的.
  静态构造函数,用于初始化任何静态数据,或用于执行仅需执行一次的特定操作。在创建第一个实例或引用任何静态成员之前,将自动调用静态构造函数。,其方式与用于初始化实例数据的实例构造函数一样。静态构造函数与实例构造函数在使用规则上面有一些区别。与实例构造函数不一样,静态构造函数不能重载,所以可用的静态构造函数只有一个默认的无参静态构造函数。静态构造函数也不能显式的调用,不能在派生类中继承,但是在创建基类类型时可以调用。

  C#在使用静态构造函数时的几个原则:
   1.静态构造函数在创建类的实例之前调用,因此在所有实例构造函数之前调用。
   2.静态构造函数在创建类的第一个实例之前调用。
   3.静态构造函数在引用静态字段之前调用。

下面是简单例子:
     class  Test
    
{
        
static Test()
        
{
            Console.WriteLine(
"a");
        }


        
public Test()
        
{
            Console.WriteLine(
"b");
        }

    }

    
class  TestOther : Test
    
{
        
public TestOther()
        
{
            Console.WriteLine(
"c");
        }

    }

则:
    Test t1  =   new  Test();
    Test t2 
=   new  Test();
    TestOther t3 
=   new  TestOther();

输出为:a,b,b,b,c

静态构造函数只调用了一次,但这种方式实现Singleton模式有个缺陷,构造函数不能带参数,不过并没有很大影响.


关于C#静态构造函数的几点说明

静态构造函数是C#的一个新特性,其实好像很少用到。不过当我们想初始化一些静态变量的时候就需要用到它了。这个构造函数是属于类的,而不是属于哪里实例的,就是说这个构造函数只会被执行一次。也就是在创建第一个实例或引用任何静态成员之前,由.NET自动调用。
  

class  SimpleClass
{
    
//  Static constructor
     static  SimpleClass()
    {
        
//
    }
}

  在使用静态构造函数的时候应该注意几点:

  1、静态构造函数既没有访问修饰符,也没有参数。因为是.NET调用的,所以像public和private等修饰符就没有意义了。
  
  2、是在创建第一个类实例或任何静态成员被引用时,.NET将自动调用静态构造函数来初始化类,也就是说我们无法直接调用静态构造函数,也就无法控制什么时候执行静态构造函数了。

  3、一个类只能有一个静态构造函数。

  4、无参数的构造函数可以与静态构造函数共存。尽管参数列表相同,但一个属于类,一个属于实例,所以不会冲突。

  5、最多只运行一次。

  6、静态构造函数不可以被继承。

  7、如果没有写静态构造函数,而类中包含带有初始值设定的静态成员,那么编译器会自动生成默认的静态构造函数。


C#静态构造函数及静态变量学习

静态构造函数:

(1)用于对静态字段、只读字段等的初始化。              

(2)添加static关键字,不能添加访问修饰符,因为静态构造函数都是私有的。        

(3)类的静态构造函数在给定应用程序域中至多执行一次:只有创建类的实例或者引用类的任何静态成员才激发静态构造函数

(4)静态构造函数是不可继承的,而且不能被直接调用。            

(5)如果类中包含用来开始执行的 Main 方法,则该类的静态构造函数将在调用 Main 方法之前执行。    

(6)任何带有初始值设定项的静态字段,则在执行该类的静态构造函数时,先要按照文本顺序执行那些初始值设定项。  

(7)如果没有编写静态构造函数,而这时类中包含带有初始值设定的静态字段,那么编译器会自动生成默认的静态构造函数。

 经典例子:

/**//**************************************************
* 静 态 构 造 函 数 练 习
* (1)①②③……为执行顺序
* (2)输出结果: static A()
* static B()
* X = 1, Y = 2
***************************************************/
using System;
class A
{
public static int X;

static A() //④ 执行完后返回到③
{
X = B.Y + 1;
Console.WriteLine("static A()");
}
}

class B
{
public static int Y = A.X + 1; //③ 调用了A的静态成员,
// 转到A的静态构造函数---->

static B() //② 如果带有初始值设定项的静态字段,
// 执行该类的静态构造函数时,
// 先要按照文本顺序执行那些初始值设定项。
// 转到初始值设定项---->
{
Console.WriteLine("static B()");
}

static void Main() //① 程序入口,
// 如果类中包含用来开始执行的 Main 方法,
// 该类的静态构造函数将在调用 Main 方法之前执行。
// 转到B的静态构造函数---->
{
Console.WriteLine("X = {0}, Y = {1}", A.X, B.Y);//⑤ 输出结果
Console.ReadLine();
}
}




C#构造函数的运用浅析

http://www.csharpwin.com/csharpspace/6762r9362.shtml

C#构造函数的名字不能随便起,必须让编译器认得出才可以被自动执行。它的命名方法既简单又合理:让C#构造函数与类同名。除了名字外,C#构造函数的另一个特别之处是没有返回值类型,这与返回值类型为void的函数不同。如果它有返回值类型,那么编译器将不知所措。在你可以访问一个类的方法、属性或任何其它东西之前, 第一条执行的语句是包含有相应类的C#构造函数。甚至你自己不写一个C#构造函数,也会有一个缺省C#构造函数提供给你。

 
  
  1. class TestClass  
  2. {  
  3.  public TestClass(): base() {} // 由CLR提供  
  4. }  

    下面列举了几种类型的C#构造函数

    1)缺省C#构造函数

 
  
  1. class TestClass  
  2. {  
  3.  public TestClass(): base() {}   
  4. }  

    上面已介绍,它由系统(CLR)提供。

    2)实例C#构造函数

    实例C#构造函数是实现对类中实例进行初始化的方法成员。如:

 
  
  1. using System;  
  2. class Point  
  3. {  
  4.  public double x, y;  
  5.  public Point()   
  6.  {  
  7. this.x = 0;  
  8. this.y = 0;  
  9.  }  
  10.  
  11.  public Point(double x, double y)  
  12.  {  
  13. this.x = x;  
  14. this.y = y;  
  15.  }  
  16.  …  
  17. }  
  18.  
  19. class Test  
  20. {  
  21.  static void Main()   
  22.  {  
  23. Point a = new Point();  
  24. Point b = new Point(3, 4); // 用C#构造函数初始化对象  
  25. …  
  26.  }  
  27. }  

    声明了一个类Point,它提供了两个C#构造函数。它们是重载的。一个是没有参数的PointC#构造函数和一个是有两个double参数的PointC#构造函数。如果类中没有提供这些C#构造函数,那么会CLR会自动提供一个缺省C#构造函数的。但一旦类中提供了自定义的C#构造函数,如Point()和Point(double x, double y),则缺省C#构造函数将不会被提供,这一点要注意。

    3) 静态C#构造函数

    静态C#构造函数是实现对一个类进行初始化的方法成员。它一般用于对静态数据的初始化。静态C#构造函数不能有参数,不能有修饰符而且不能被调用,当类被加载时,类的静态C#构造函数自动被调用。如:

 
  
  1. using System.Data;  
  2. class Employee  
  3. {  
  4.  private static DataSet ds;  
  5.  static Employee()  
  6.  {  
  7. ds = new DataSet(...);  
  8.  }  
  9.  ...  
  10. }  

    声明了一个有静态C#构造函数的类Employee。注意静态C#构造函数只能对静态数据成员进行初始化,而不能对非静态数据成员进行初始化。但是,非静态C#构造函数既可以对静态数据成员赋值,也可以对非静态数据成员进行初始化。

    如果类仅包含静态成员,你可以创建一个private的C#构造函数:private TestClass() {…},但是private意味着从类的外面不可能访问该C#构造函数。所以,它不能被调用,且没有对象可以被该类定义实例化。

    以上是几种类型C#构造函数的简单运用,下面将重点介绍一下在类的层次结构中(即继承结构中)基类和派生类的C#构造函数的使用方式。派生类对象的初始化由基类和派生类共同完成:基类的成员由基类的C#构造函数初始化,派生类的成员由派生类的C#构造函数初始化。

    当创建派生类的对象时,系统将会调用基类的C#构造函数和派生类的C#构造函数,构 造函数的执行次序是:先执行基类的C#构造函数,再执行派生类的C#构造函数。如果派生类又有对象成员,则,先执行基类的C#构造函数,再执行成员对象类的C#构造函数,最后执行派生类的C#构造函数。

    至于执行基类的什么C#构造函数,缺省情况下是执行基类的无参C#构造函数,如果要执行基类的有参C#构造函数,则必须在派生类C#构造函数的成员初始化表中指出。如:

 
  
  1. class A  
  2. private int x;  
  3.  public A( ) { x = 0; }  
  4.  public A( int i ) { x = i; }  
  5. };  
  6.  
  7. class B : A  
  8. private int y;  
  9.  public B( ) { y = 0; }  
  10.  public B( int i ) { y = i; }  
  11.  public B( int i, int j ):A(i) { y = j; }  
  12. };  
  13.  
  14. B b1 = new B();   
  15. //执行基类A的C#构造函数A(),再执行派生类的C#构造函数B()  
  16. B b2 = new B(1);   
  17. //执行基类A的C#构造函数A(),再执行派生类的C#构造函数B(int)  
  18. B b3 = new B(0,1);   
  19. //执行执行基类A的C#构造函数A(int) ,再执行派生类的   

    C#构造函数B(int,int)

    在这里C#构造函数的执行次序是一定要分析清楚的。另外,如果基类A中没有提供无参C#构造函数public A( ) { x = 0; },则在派生类的所有C#构造函数成员初始化表中必须指出基类A的有参C#构造函数A(i),如下所示:

 
  
  1. class A  
  2. private int x;  
  3.  public A( int i ) { x = i; }  
  4. };  
  5.  
  6. class B : A  
  7. private int y;  
  8.  public B():A(i) { y = 0; }  
  9.  public B(int i):A(i) { y = i; }  
  10.  public B(int i, int j):A(i) { y = j; }  
  11. };   

    C#构造函数的运用就向你介绍到这里,希望对你学习C#构造函数的运用有所帮助。


单例模式学习

http://www.cnblogs.com/yaunion/archive/2011/05/10/2042074.html

(一):从静态类和静态构造器说起

静态类和静态构造器(或叫静态构造函数)是深入理解单例模式的基础知识
一、静态类
C# 2.0 提供了静态类,在1.x中我们要实现静态类需要使用下面的代码。

1.0
public sealed class Class1
{
private Class1(){}
}


在C# 2.0中我们可以使用static class来更加优雅地解决这个问题。
public static class Class1
{
}


我们反编译一下,会了解其实现机制。

.class public abstract auto ansi sealed beforefieldinit Program
extends object
{
}


原来编译器将该类声明为 abstract sealed,自然不能被继承被实例化了。
从这段反编译的代码我们可以获知一个很重要的信息:static class机制只是编译时的处理,CLR的
运行时机制并没有因为静态类的出现而发生改变。
但是C#编译器并不允许我们在代码中直接声明一个abstract sealed类型,下面的代码无法通过编译。

public abstract sealed class Class1
{
}


静态类的限制

1. 静态类不能有实例构造器。
2. 静态类不能有任何实例成员。
3. 静态类上不能使用abstract和sealed修饰符。
4. 静态类默认继承自System.Object,不能显式指定任何其他基类。
5. 静态类不能指定任何接口实现。
6. 静态类的成员不能有protected或者protected internal访问保护修饰符。
以下是MSDN上对静态类的描述:    
当将类声明为static时,以指示它仅包含静态成员。不能使用 new 关键字创建静态类的实例。静态类在加载包含该类的程序或命名空间时由 .NET Framework 公共语言运行库 (CLR) 自动加载。
使用静态类来包含不与特定对象关联的方法。例如,创建一组不操作实例数据并且不与代码中的特定对象关联的方法是很常见的要求。您应该使用静态类来包含那些方法。
静态类的主要功能如下:

它们仅包含静态成员。

它们不能被实例化。

它们是密封的。

它们不能包含实例构造函数
关于静态类的更具体描述,请参考
http://msdn2.microsoft.com/zh-cn/library/79b3xss3(VS.80).aspx
http://www.codeproject.com/useritems/C__20_static_class.asp
    我们有些时候需要将一堆静态方法放在一个类中,而这个类又没有任何实例成员,比如 System.Web.HttpUtility 和.Net框架中的Math库就是这样的例子,由于没有任何实例成员,继承或者实例化都没有任何意义,因此静态类还是有用的。

二、静态构造器(或叫静态构造函数):
静态构造函数,可以在C#中用于初始化类数据,其方式与用于初始化实例数据的实例构造函数一样。静态构造函数与实例构造函数在使用规则上面有一些区别。与实例构造函数不一样,静态构造函数不能重载,所以可用的静态构造函数只有一个默认的无参静态构造函数(也不能添加private和public这样的关键字)。静态构造函数也不能显式的调用,不能在派生类中继承,但是在创建基类类型时可以调用。
C#在使用静态构造函数时的几个原则:
1.静态构造函数在创建类的实例之前调用,因此在所有实例构造函数之前调用。
2.静态构造函数在创建类的第一个实例之前调用。
3.静态构造函数在引用静态字段之前调用。
4.静态构造函数只能用于对静态字段的初始化。              
5.添加static关键字,不能添加访问修饰符,因为静态构造函数都是私有的。        
6.类的静态构造函数在给定应用程序域(AppDomain)中至多执行一次:只有创建类的实例或者引用类的任何静态成员才激发静态构造函数
7.静态构造函数是不可继承的,而且不能被直接调用。            
8.如果类中包含用来开始执行的 Main 方法,则该类的静态构造函数将在调用 Main 方法之前执行。    
9.任何带有初始值设定项的静态字段,则在执行该类的静态构造函数时,先要按照文本顺序执行那些初始值设定项。  


      class Test
    {
        static Test()
        {
            Console.WriteLine("a");
        }

        public Test()
        {
            Console.WriteLine("b");
        }
    }
    class Test1 : Test
    {
        public Test1()
        {
            Console.WriteLine("c");
        }
    }
实例化的时候

    Test t = new Test(); //首先调用Test的静态构造器输出a,然后调用Test的实例构造器输出b
    Test t1 = new Test();//调用Test的实例构造器输出b
    Test1 t2 = new Test1();//调用Test的实例构造器输出b,然后调用Test1的实例构造器输出c
因此最后的输出为:a,b,b,b,c
静态构造函数只调用了一次。
再来看一个示例:
在此示例中,类 Bus 有一个静态构造函数和一个静态成员 Drive()。当调用 Drive() 时,将调用静态构造函数来初始化类。
C#
复制代码
public class Bus
{
    // Static constructor:
    static Bus()
    {
        System.Console.WriteLine("The static constructor invoked.");
    }

    public static void Drive()
    {
        System.Console.WriteLine("The Drive method invoked.");
    }
}

class TestBus
{
    static void Main()
    {
        Bus.Drive();
    }
}
输出的结果如下:
The static constructor invoked.

The Drive method invoked.
要记住一点,静态构造器总是在实例构造器之前被调用。(静态类中可以存在静态构造器,但不允许存在实例构造器)
再来看一个例子:
/**************************************************
*            静 态 构 造 函 数 练 习
* (1)①②③……为执行顺序
* (2)输出结果: static A()
*                 static B()
*                 X = 1, Y = 2
***************************************************/
    class A
    {
        public static int X;
        static A()           //④ 执行完后返回到③
        {
            X = B.Y + 1;
            Console.WriteLine("static A()");
        }
    }
    class B
    {
        public static int Y = A.X + 1;      //③ 调用了A的静态成员,
        //   转到A的静态构造函数---->
        static B()           //② 如果带有初始值设定项的静态字段,
        //   执行该类的静态构造函数时,
        //   先要按照文本顺序执行那些初始值设定项。
        //   转到初始值设定项---->
        {
            Console.WriteLine("static B()");
        }
        static void Main()         //① 程序入口,
        //   如果类中包含用来开始执行的 Main 方法,
        //   该类的静态构造函数将在调用 Main 方法之前执行。
        //   转到B的静态构造函数---->
        {
            Console.WriteLine("X = {0}, Y = {1}", A.X, B.Y);//⑤ 输出结果
            Console.ReadLine();
        }
    }
关于静态构造器更详细的描述,请参考:
http://msdn2.microsoft.com/zh-cn/library/k9x6w0hc(VS.80).aspx
http://www.yaosansi.com/blog/article.asp id=730

三、前面介绍了静态类和静态构造器的基本知识,下面我们来理解一些和单例模式相关的知识
1. BeforeFieldInit标记
静态构造器(static constructors)与类型初始化器(type initializers)的关系
静态构造器的定义:
The C# specification (ECMA 334) states in section 17.11:

The static constructor for a class executes at most once in a given application domain. The execution of a static constructor is triggered by the first of the following events to occur within an application domain:
An instance of the class is created.
Any of the static members of the class are referenced.

也就是说当类被实例化或者类的静态成员被引用的时候静态构造器被调用。在同一个AppDomain中,某个类的静态构造器最多被调用一次。
再来看类型初始化器的定义:
The CLI specification (ECMA 335) states in section 8.9.5:
A type may have a type-initializer method, or not.
A type may be specified as having a relaxed semantic for its type-initializer method (for convenience below, we call this relaxed semantic BeforeFieldInit)
If marked BeforeFieldInit then the type's initializer method is executed at, or sometime before, first access to any static field defined for that type
If not marked BeforeFieldInit then that type's initializer method is executed at (i.e., is triggered by):
first access to any static or instance field of that type, or
first invocation of any static, instance or virtual method of that type

也就是说系统会有一种机制决定什么时候类型初始化器被调用(由系统自身维护的一个BeforeFieldInit来决定)
当BeforeFieldInit被标记时,类型初始化器将在首次访问这个类型的静态字段时或者之前被调用(也就是说类型初始化器被调用的时间不确定,你只能确定它调用的时间<=你首次访问类型的静态字段的时间)
当BeforeFieldInit未被标记时,类型初始化器将在首次访问该类型的成员时被调用(不论是静态成员还是实例成员)。
现在让我们来进入问题的关键:C#的定义中指出当只有在一个类型不具备静态构造器时它的BeforeFieldInit才会被自动标记上。事实上,这是由编译器帮我们完成的,它可能会导致一些我们意想不到的效果。
最后我要再次强调,静态构造器并不等同于类型初始化器。任何类型都有类型初始化器,但不一定有静态构造器
静态构造器是什么我们已经知道了,但类型初始化器到底是什么呢?
类型初始化器实际上负责帮我们初始化静态字段。假设我们定义了这样一条字段,static object o = new object();如果该字段所在的类没有静态构造器,那么o的初始化就是类型初始化器帮我们完成的,反之o的初始化由静态构造器负责。
是不是觉得很难理解呢?那我们就来看一个具体的例子吧:
class Test //没有静态构造器,BeforeFieldInit被标记
{
    static object o = new object();
}


class Test
{
    static object o;

    static Test() //有静态构造器,BeforeFieldInit未被标记
    {
        o = new object();
    }
}

你认为上面的两个类是等价的吗?

实际上以上两个类并不等价。由于第一个类没有静态构造器,因此它的BeforeFieldInit被标记了,而第二个类由于有静态构造器它的BeforeFieldInit没有被标记。因此它们的类型初始化器的调用时间并不相同。具体的调用时间请参考前面的描述。
再来看一个类
class Test
{
    static object o = new object();

    static Test()
    {
    }
}
    这个类和上面的第二个类是等价的

    为什么我们需要关注BeforeFieldInit是否被标记呢?以第三个类为例。当我们为Test添加一个空的静态构造器,它的BeforeFieldInit会被设置为未标记。这样我们就可以保证o直到该类型的字段第一次被访问或方法第一次被调用时才会被初始化,这样就可以实现惰性加载了。
   如果我们不添加这样一个空的静态构造器,我们就无法知道o什么时候被初始化(只能确定它在该类型的字段第一次被访问之前)

(二)具体实现

首先看一个最常见的单例模式的实现,也是很多人常用的一种方式:

Singleton 设计模式的下列实现采用了 Design Patterns: Elements of Reusable Object-Oriented Software[Gamma95]

中所描述的解决方案,但对它进行了修改,以便利用 C# 中可用的语言功能,如属性:

版本1:非线程安全的实现

// Bad Code ! Do not use!

 

public sealed class Singleton

{

    static Singleton instance=null;

    Singleton()

    {

    }

 

    public static Singleton Instance

    {

        get

        {

            if (instance==null)

            {

                instance = new Singleton();

            }

            return instance;

        }   }}

该实现主要有两个优点:

由于实例是在 Instance 属性方法内部创建的,因此类可以使用附加功能(例如,对子类进行实例化),即使它可能引入

不想要的依赖性。

直到对象要求产生一个实例才执行实例化;这种方法称为"懒实例化"。懒实例化避免了在应用程序启动时实例化不必要的

singleton。

但是,这种实现的主要缺点是在多线程环境下它是不安全的。

如果执行过程的不同线程同时判断if(instance==null)语句,发现instance为null,那就可能会创建多个 Singleton 对象实例。

解决此问题的方法有很多。

版本二:线程安全简洁版

public sealed class Singleton

{

    static Singleton instance=null;

    static readonly object padlock = new object();

    Singleton()

    {

    }

    public static Singleton Instance

    {

        get

        {

            lock (padlock)

            {

                if (instance==null)

                {

                    instance = new Singleton();

                }

                return instance;

            }     } } }

 

(三)

在第二个版本中,我们做到了线程安全。同时我们也实现了惰性加载机制。

这个版本的唯一不足之处是lock可能会对大量的并发访问的效率造成影响。但一般的应用中这样的效率损失可以忽略不计

如果访问的效率对我们性命攸关,那我们可以改进到第三个版本

版本三:双检锁(double-check locking)保证线程安全

 

// Bad Code ! Do not use!

public sealed class Singleton

{

    static Singleton instance=null;

    static readonly object padlock = new object();

    Singleton()

    {

    }

  public static Singleton Instance

    {

        get

        {

            if (instance==null)

            {   //@位置1   此位置可能有多个线程处于waitzhuangtai

                lock (padlock)

                {

                   //重复判断一次,即使在@位置1已经有多个线程涌入的情况下仍然能保证不会重复初始化Singleton

                    if (instance==null)

                    {

                        instance = new Singleton();

                    }    }      }

           return instance;

        }   } }

 

你可以对上面的代码进行一个思考,看上去双检锁机制似乎提高了访问的效率也保证了线程安全。但其实这样的写法在很多

平台和优化编译器上是错误的。

原因在于:instance = new Singleton();这行代码在不同编译器上的行为是无法预知的。一个优化编译器可以合法地如下实现

instance = new Singleton();

1. instance = 给新的实体分配内存

2. 调用Singleton的构造函数来初始化instance的成员变量((这里的初始化指的是初始化instance的实例成员,因为Singleton

的静态成员已经初始化过了)

现在想象一下有线程A和B在调用instance,线程A先进入,在执行到步骤1的时候被踢出了cpu。然后线程B进入,B看到的是

instance已经不是null了

(内存已经分配),于是它开始放心地使用instance,但这个是错误的,因为在这一时刻,instance的成员变量还都是缺省值,

A还没有来得及执行步骤2来完成instance的初始化。

当然编译器也可以这样实现:

1. temp = 分配内存

2. 调用temp的构造函数

3. instance = temp

如果编译器的行为是这样的话我们似乎就没有问题了,但事实却不是那么简单,因为我们无法知道某个编译器具体是怎么做的。

要解决这个问题,我们可以利用 内存墙机制(MemoryBarrier)来解决这个问题,上面的代码改写如下:

 

版本三改正版1

public sealed class Singleton

{

    static Singleton instance=null;

    static readonly object padlock = new object();

    Singleton()

    {

    }

    public static Singleton Instance

    {

        get

        {

            if (instance==null)

            {

                lock (padlock)

                {

                    if (instance==null)

                    {

                        Singleton newVal = new Singleton();

                        System.Threading.Thread.MemoryBarrier();

                        instance = newVal;   

                    }      }      }

            return instance;

        } } }

 

版本三改正版2

public sealed class Singleton

{

    static volatile Singleton instance=null;

    static readonly object padlock = new object();

    Singleton()

    {

    }

    public static Singleton Instance

    {

        get

        {

            if (instance==null)

            {

                lock (padlock)

                {

                    if (instance==null)

                    {

                        instance = new Singleton();

                    }        }       }

            return instance;

        }   } }

   以上谈到的一些如多线程安全、双险锁、内存墙、等概念涉及到很多编译原理和汇编的知识,由于个人能力有限,也没法进一步加以详细阐释,大家有兴趣的话参考一下以下一些网址吧:

http://msdn.microsoft.com/msdnmag/issues/05/10/MemoryModels/default.aspx

http://blogs.msdn.com/brada/archive/2004/05/12/130935.aspx

http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html

http://blog.joycode.com/demonfox/archive/2007/01/04/90894.aspx

http://www.cnblogs.com/dayouluo/archive/2005/12/25/304455.html

 

好了,到此为止,我们在第三个版本的两个改进版中同时兼顾了效率、线程安全和惰性加载。

但这两个改进版虽然从应用上没有问题,但似乎又涉及了过多的专业知识,把问题复杂化了,

让人顿生生疏之感。

既然如此,让我们再来看一个亲切一点的版本吧:

版本四:简单实现,非惰性加载

public sealed class Singleton

 

{

   private static readonly Singleton instance = new Singleton();

   private Singleton(){}

   public static Singleton Instance

   {

      get

      {

         return instance;

      }   } }

 

这种实现简单,线程安全,缺陷主要是instance不是惰性加载的。准确的说是不一定是惰性加载的,因为我们无法得知instance

会在什么时候被初始化。若对我的描述有疑虑,请参考单例模式深入研究(一)。


宁可去碰壁,也不在家面壁;缘于自然,顺其自然。



你可能感兴趣的:(.NET,windows,C#)