在 C# 中实现 Singleton

Leave a Comment2009.12.23 12:51 by Felicia 

我们需要只有一个实例的类,并且需要提供一个用于访问实例的全局访问点,还希望确保解决方案是线程安全的。

下面的实现仅允许一个线程在尚未创建 Singleton 实例的情况下进入关键区域(该区域由 lock 块标识)。

using System;
public sealed class Singleton
{
  
private static volatile Singleton instance;
  
private static object syncRoot = new Object();
  
private Singleton() {}
  
public static Singleton Instance
  
{
      
get 
      
{
        
if (instance == null) 
        
{
            
lock (syncRoot) 
            
{
              
if (instance == null) 
                  
instance = new Singleton();
            
}
        
}
        
return instance;
      
}
  
}
}

I got this when I renamed my C# project then tried to publish it. To solve, I went to the “Signing” tab of the project properties and unchecked “Sign the ClickOnce manifests”.

Good luck!

C# Accurate Timer

Leave a Comment2009.10.12 10:59 by Felicia 

C# 有三个标准定时器,分别是 System.Windows.Forms.Timer, System.Threading.Timer, System.Timers.Timer。
这三个Timer都不是很准确,无法进行精确到1毫秒的定时。经测试,这三种Timer的最小触发时间间隔是大约15毫秒。
因此我们必须寻找另外的方案。

Windows提供了用于多媒体的winmm.dll,可以满足高精度定时的要求。
下面是winmm.dll提供的API的C#包装。

public class MMTimer : IDisposable
{
    
//Lib API declarations
    
[DllImport("Winmm.dll", CharSet = CharSet.Auto)]
    
static extern uint timeSetEvent(uint uDelay, uint uResolution, TimerCallback lpTimeProc, UIntPtr dwUser, uint fuEvent);
 
    
[DllImport("Winmm.dll", CharSet = CharSet.Auto)]
    
static extern uint timeKillEvent(uint uTimerID);
 
    
[DllImport("Winmm.dll", CharSet = CharSet.Auto)]
    
static extern uint timeGetTime();
 
    
[DllImport("Winmm.dll", CharSet = CharSet.Auto)]
    
static extern uint timeBeginPeriod(uint uPeriod);
 
    
[DllImport("Winmm.dll", CharSet = CharSet.Auto)]
    
static extern uint timeEndPeriod(uint uPeriod);
 
    
//Timer type definitions
    
[Flags]
    
public enum fuEvent : uint
    
{
        
TIME_ONESHOT = 0,      //Event occurs once, after uDelay milliseconds.
        
TIME_PERIODIC = 1,
        
TIME_CALLBACK_FUNCTION = 0x0000/* callback is function */
        
//TIME_CALLBACK_EVENT_SET = 0x0010, /* callback is event - use SetEvent */
        
//TIME_CALLBACK_EVENT_PULSE = 0x0020  /* callback is event - use PulseEvent */
    
}
 
    
//Delegate definition for the API callback
    
delegate void TimerCallback(uint uTimerID, uint uMsg, UIntPtr dwUser, UIntPtr dw1, UIntPtr dw2);
 
    
//IDisposable code
    
private bool disposed = false;
 
    
public void Dispose()
    
{
        
Dispose(true);
        
GC.SuppressFinalize(this);
    
}
 
    
private void Dispose(bool disposing)
    
{
        
if (!this.disposed)
        
{
            
if (disposing)
            
{
                
Stop();
            
}
        
}
        
disposed = true;
    
}
 
    ~
MMTimer()
    
{
        
Dispose(false);
    
}
 
    
/// <summary>
    
/// The current timer instance ID
    
/// </summary>
    
uint id = 0;
 
    
/// <summary>
    
/// The callback used by the the API
    
/// </summary>
    
TimerCallback thisCB;
 
    
/// <summary>
    
/// The timer elapsed event
    
/// </summary>
    
public event EventHandler Timer;
    
protected virtual void OnTimer(EventArgs e)
    
{
        
if (Timer != null)
            
Timer(this, e);
    
}
 
    
public MMTimer()
    
{
        
//Initialize the API callback
        
thisCB = CBFunc;
    
}
 
    
/// <summary>
    
/// Stop the current timer instance (if any)
    
/// </summary>
    
public void Stop()
    
{
        
lock (this)
        
{
            
if (id != 0)
            
{
                
timeKillEvent(id);
                
Console.WriteLine("MMTimer " + id.ToString() + " stopped");
                
id = 0;
            
}
        
}
    
}
 
    
/// <summary>
    
/// Start a timer instance
    
/// </summary>
    
/// <param name="ms">Timer interval in milliseconds</param>
    
/// <param name="repeat">If true sets a repetitive event, otherwise sets a one-shot</param>
    
public void Start(uint ms, bool repeat)
    
{
        
//Kill any existing timer
        
Stop();
 
        
//Set the timer type flags
        
fuEvent f = fuEvent.TIME_CALLBACK_FUNCTION | (repeat ? fuEvent.TIME_PERIODIC : fuEvent.TIME_ONESHOT);
 
        
lock (this)
        
{
            
id = timeSetEvent(ms, 0, thisCB, UIntPtr.Zero, (uint)f);
            
if (id == 0)
                
throw new Exception("timeSetEvent error");
            
Console.WriteLine("MMTimer " + id.ToString() + " started");
        
}
    
}
 
    
void CBFunc(uint uTimerID, uint uMsg, UIntPtr dwUser, UIntPtr dw1, UIntPtr dw2)
    
{
        
//Callback from the MMTimer API that fires the Timer event. Note we are in a different thread here
        
OnTimer(new EventArgs());
    
}
}

今年做的最大的决定,就是转专业到计科了。我在转专业之前考虑了很久,最终确定我的确比较适合学习计算机,之后就毫不犹豫的转了。因为是大二下转专业,所以我要补修非常多的课。其实这个学期还好,也就比同班的人多上了大学语文,数字逻辑,c语言。不过由于这个学期比赛比较多,final回来之后又陆续参加了一些小的比赛,所以平时的课有的没有办法上了。期末的时候学习非常紧张,考试频繁,很多东西我又是第一次接触。比如我先学微机系统与接口技术,再学数字逻辑,再学汇编语言,完全是跟正常的专业培养方案反过来了。还好我发现自己对计算机专业的知识有较强的领悟能力,一切都还能掌握。期末考试之前我采用两天复习法,每天复习两小时,基本上搞定所有的课。就等出成绩啦,嘿嘿!
[Read more]