用C#语言泛化单件模式

 

本人对于C#只能算是初学者,写此随笔,也只为和大家一起讨论,共同进步。

 

我看到过一些用C#语言泛化单件(Singleton)的文章和代码,里面有个问题,即用new来创建对象,比如类似下面这段代码:

 

if  (_instance  ==   null )
{
    _instance 
=   new  T();
}

 

要想让其工作,你必须让T的构造函数为public。但是,如果T的构造函数为public,那任何客户代码都可调用new T()。你无法用语言本身限制其只能被创建最多一次和只有一个全局访问点,这样也就无法保证你的单件成为“单件”。

 

C++里有友元(friend),T的构造函数可是设为non-public,然后用单件的模板类作为友元去访问它。用ACE的单件模板类ACE_Singleton时,就是如此实现。但C#没有友元。

 

CodeProject有篇文章:Generic Singleton Pattern using Reflection, in C#。作者用.Net反射机制实现了泛化的单件,重要的是它可以用具有non-public构造函数的public类来实例化。他用Type.GetConstructor来找到non-public的构造函数,并调用它来创建实例。他的代码如下(我去掉了异常处理部分):

 

ConstructorInfo constructor  =   typeof (T).GetConstructor(BindingFlags.Instance  |  BindingFlags.NonPublic,  null new  Type[ 0 ],  null );
instance 
=  (T)constructor.Invoke( null );

 

我仿照它写了我自己的泛化Singleton,见下:

 

     public   static   class  Singleton < T >   where  T :  class
    {
        
private   static   volatile  T _instance;
        
private   static   object  _lock  =   new   object ();

         public   static  T Instance
        {
            
get
            {
                
if  (_instance  ==   null )
                {
                    
lock  (_lock)
                    {
                        
if  (_instance  ==   null )
                        {
                            Type type 
=   typeof (T);
                            ConstructorInfo ctor;
                            ctor 
=  type.GetConstructor(BindingFlags.Instance  |  BindingFlags.Public  |  BindingFlags.NonPublic,
                                          
null new  Type[ 0 ],  new  ParameterModifier[ 0 ]);
                            _instance 
=  (T)ctor.Invoke( new   object [ 0 ]);
                        }
                    }
                }

                
return  _instance;
            }
        }
    }

 

当使用它时,客户代码是这样的:

 

     public   sealed   class  ZoomTool : BaseTool
    {
        
#region  Constructor

        
private  ZoomTool()
        {
        }

        
#endregion

        
#region  Properties

        ......

        
public   static  ZoomTool Instance
        {
            
get  {  return  Singleton < ZoomTool > .Instance; }
        }

        
#endregion
    }

 

使用ZoomTool单件时代码是这样:

 

_mapToolTypeToTool.Add(ToolType.Zoom, ZoomTool.Instance); 

 

但是这种泛型单件有一个问题:我得到了Code Analysis的CA1000警告:“不要在泛型类型中声明静态成员(Do not declare static members on generic types)”。

 

于是我将泛型类Singleton<T>改为普通类,将其中的Instance函数改为GetInstance<T>泛型函数,写下了另一个泛化的单件。

 

     public   static   class  Singleton
    {
        
private   static   class  Storage < T >   where  T :  class
        {
            
internal   static   volatile  T _instance;
        }

        
private   static   object  _lock  =   new   object ();

        [System.Diagnostics.CodeAnalysis.SuppressMessage(
" Microsoft.Design " " CA1004:GenericMethodsShouldProvideTypeParameter " )]
        
public   static  T GetInstance < T > ()  where  T :  class
        {
            
if  (Storage < T > ._instance  ==   null )
            {
                
lock  (_lock)
                {
                    
if  (Storage < T > ._instance  ==   null )
                    {
                        Type type 
=   typeof (T);
                        ConstructorInfo ctor;
                        ctor 
=  type.GetConstructor(BindingFlags.Instance  |  BindingFlags.Public  |  BindingFlags.NonPublic,
                                      
null new  Type[ 0 ],  new  ParameterModifier[ 0 ]);
                        Storage
< T > ._instance  =  (T)ctor.Invoke( new   object [ 0 ]);
                    }
                }
            }
            
return  Storage < T > ._instance;
        }
    }
}

 

这时客户代码是这样的:

 

     public   sealed   class  ZoomTool : BaseTool
    {
        
#region  Constructor

        
private  ZoomTool()
        {
        }

        
#endregion

        
#region  Properties

        ......

        
public   static  ZoomTool Instance
        {
            
get  {  return  Singleton.GetInstance < ZoomTool > (); }
        }

        
#endregion
    }

 

但我得到了另一个Code Analysis警告CA1004:“泛型方法应提供类型参数(Generic methods should provide type parameter)”。

 

MSDN里不推荐压制这两个消息(SuppressMessage),我感觉是泛型技术里有些规则限制的。我不太明白为什么要提示这2个警告。希望有经验的人,能说说自己的理解。先谢过了!

 

你可能感兴趣的:(C#)