C# 泛型+扩展方法

8 评论209次阅读2010.10.15 17:17 作者:Felicia 编辑

[阅读更多]

C# 3.0及以后版本提供了扩展方法这一强大工具,使得动态扩展类变得十分方便。具体使用方法是定义一个static class,然后定义static扩展方法,注意扩展方法的第一个参数必须用this关键字修饰。扩展方法能像类本身定义的方法一样被使用,而不需要修改类的代码,这样扩展原有库中的类就变得非常容易了。扩展方法同样对接口生效,更牛X的是,扩展方法中同样可以使用泛型。

下面是一个例子,展示了怎样扩展IEnumerable接口,增加一个RandomSelect的方法用于在表中随机选取元素。

public static class IEnumerableExtensions
{
    public static IEnumerable<T> RandomSelect<T>(this IEnumerable<T> input, int outputSize)
    {
        int size = input.Count();

        if (outputSize < 0)
        {
            outputSize = 0;
        }
        if (outputSize > size)
        {
            outputSize = size;
        }

        List<int> index = new List<int>();
        for (int i = 0; i < size; i++)
        {
            index.Add(i);
        }

        List<T> ret = new List<T>();
        Random rand = new Random();
        for (int i = 0; i < outputSize; i++)
        {
            int r = rand.Next() % (size - i);
            ret.Add(input.ElementAt(index[r]));
            index[r] = index[size - i - 1];
        }

        return ret;
    }
}

使用方法和原生方法是一样一样的:)

List sourceList = new List() {1, 2, 3, 4, 5};
IEnumerable randomSelectedList = sourceList.RandomSelect(3);
标签, , , | 日志分类:C#, 精华

在 C# 中实现 Singleton

发表评论2次阅读2009.12.23 12:51 作者: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;
      
}
  
}
}
标签, , | 日志分类:C#
[阅读更多]

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#

C# Accurate Timer

发表评论46次阅读2009.10.12 10:59 作者: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#

转到计科的第一学期结束了

发表评论8次阅读2008.07.01 21:28 作者:Felicia 编辑

[阅读更多]

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

标签, , , , | 日志分类:心情日记