110,536
社区成员
发帖
与我相关
我的任务
分享
using System;
namespace 单件模式
{
public class SingletonException:Exception
{
public SingletonException (string s):base (s)
{
}
}
public class Spooler
{
static bool instance_flag=false;
public Spooler()
{
if(instance_flag)
throw new SingletonException("已存在一个实例");
else
instance_flag=true;
Console.WriteLine("实例已打开");
}
~Spooler()
{
instance_flag=false;
}
}
class Program
{
public static void Main(string[] args)
{
Spooler pr1,pr2;
Console.WriteLine("打开一个实例");
try
{
pr1=new Spooler();
}
catch(SingletonException e)
{
Console.WriteLine(e.Message);
}
pr1=null;
GC.Collect();//这里似乎并没有什么用,请问有什么解决方案吗
Console.WriteLine("打开两个实例");
try
{
pr2=new Spooler();
}
catch(SingletonException e)
{
Console.WriteLine(e.Message);
}
Console.Write("Press any key to continue . . . ");
Console.ReadKey(true);
}
}
}
static void Main(string[] args)
{
var pr1 = new Spooler();
pr1 = new Spooler();
GC.Collect();
Console.Write("Press any key to continue . . . ");
Console.ReadKey(true);
}
你会看到,由于 pr1 引用了新的对象实例,那么在执行 GC.Collect() 时,第一个对象实例就被销毁了(销毁之前它的析构方法被执行了)。
当然实际的编程中是直接写成static void Main(string[] args)
{
var pr1 = new Spooler();
pr1 = new Spooler();
Console.Write("Press any key to continue . . . ");
Console.ReadKey(true);
}
也就是说不要画蛇添足地去手动调用 GC.Collect() 方法(有些人硬要你自己手动去调用GC.Coolect()方法,你要自己判明是否真的必要)。因为GC会在必要时自动去执行Collect方法,而通常不需要牺牲性能去为了释放一点点(一个Spooler对象)的空间。public class SingletonException : Exception
{
public SingletonException(string s) : base(s)
{
}
}
public class Spooler
{
public Spooler()
{
Console.WriteLine("实例已打开");
}
~Spooler()
{
Console.WriteLine("%%%%%");
}
}
class Program
{
static void Main(string[] args)
{
for (var i = 0; i < 1000; ++i)
t0();
Console.Write("Press any key to continue . . . ");
Console.ReadKey(true);
}
private static void t0()
{
var pr1 = new Spooler();
var pr2 = new Spooler();
pr2 = null; //实际上写这个是多余的,pr1和pr2会同时被 GC 销毁
}
}
那么运行时,你基本上看不到对象释放时的析构方法调用输出。
但是假设修改一下循环次数,例如public class SingletonException : Exception
{
public SingletonException(string s) : base(s)
{
}
}
public class Spooler
{
public Spooler()
{
Console.WriteLine("实例已打开");
}
~Spooler()
{
Console.WriteLine("%%%%%");
}
}
class Program
{
static void Main(string[] args)
{
for (var i = 0; i < 100000; ++i)
t0();
Console.Write("Press any key to continue . . . ");
Console.ReadKey(true);
}
private static void t0()
{
var pr1 = new Spooler();
var pr2 = new Spooler();
pr2 = null; //实际上写这个是多余的,pr1和pr2会同时被 GC 销毁。只要对象不用了,过一会儿自然就会被GC销毁。
}
}
或者循环更多次,耐心等待10秒钟,你可能就能从打印结果中看到了析构方法被执行的日志了。
这是因为GC是自动的、智能的。它不会动不动就起动。如果动不动就启动,有些人人为这就可以“及时”释放空间了,实际上整个程序就慢了。只有必要时GC才会启动,并不会在无需启动时提前启动,例如这里就是这种情况。public class SingletonException : Exception
{
public SingletonException(string s) : base(s)
{
}
}
public class Spooler
{
public Spooler()
{
Console.WriteLine("实例已打开");
}
~Spooler()
{
Console.WriteLine("%%%%%");
}
}
class Program
{
static void Main(string[] args)
{
t1();
var pr2 = new Spooler();
pr2 = null;
GC.Collect();
Console.Write("Press any key to continue . . . ");
Console.ReadKey(true);
}
private static void t1()
{
var pr1 = new Spooler();
}
}
这样可以清楚地看到析构方法执行了。public class SingletonException : Exception
{
public SingletonException(string s) : base(s)
{
}
}
public class Spooler
{
public Spooler()
{
Console.WriteLine("实例已打开");
}
~Spooler()
{
Console.WriteLine("%%%%%");
}
}
class Program
{
static void Main(string[] args)
{
t1();
GC.Collect();
var pr2 = new Spooler();
Console.Write("Press any key to continue . . . ");
Console.ReadKey(true);
}
private static void t1()
{
var pr1 = new Spooler();
}
}
class Singleton
{
static Singleton _instance;
public static Singleton Instance
{
get
{
if (_instance == null)
_instance = new Singleton();
return _instance;
}
}
Singleton()
{
}
}