2011-07-26 24 views
0

我正在C#中爲我的控制檯應用程序實現超時。 我有一個名爲MySession的類,它必須由Session超時綁定。這意味着在類的構造函數中,我爲所創建的對象配置了超時。如果該類中的任何方法未在指定的超時內調用,則在隨後訪問任何方法時,必須拋出Timeout異常。在C#中爲控制檯應用程序實現會話超時#

這是該類的虛擬實現。

public class MySession { 
private TimeSpan timeout; 
private DateTime lastAccessedTime; 

public MySession(TimeSpan timeout) { 
    this.timeout = timeout; 
    lastAccessedTime = DateTime.Now; 
} 

public void StoreName(string name) { 
    TimeSpan diff = DateTime.Now - lastAccessedTime; 
    if(diff.Ticks - timeout.Ticks > 0) { 
     throw new TimeoutException("session timed out"); 
    } 
    //store logic 
    lastAccessedTime = DateTime.Now; 
} 

public void StoreAddress(string address) { 
    TimeSpan diff = DateTime.Now - lastAccessedTime; 
    if(diff.Ticks - timeout.Ticks > 0) { 
     throw new TimeoutException("session timed out"); 
    } 
    //store logic 
    lastAccessedTime = DateTime.Now; 
} 

public void Commit() { 
    TimeSpan diff = DateTime.Now - lastAccessedTime; 
    if(diff.Ticks - timeout.Ticks > 0) { 
     throw new TimeoutException("session timed out"); 
    } 
    //commit logic 
    lastAccessedTime = DateTime.Now; 
}} 

我有兩個問題。

  1. 有沒有更好的方法來做到這一點,避免每個方法開始時的檢查?我明顯可以重構該代碼中的IsAlive屬性,但是仍然需要在每個方法的開頭檢查IsAlive。 .NET中是否有任何Session類可以繼承我的類?
  2. 假設,讓我說我的一個會話類中的方法返回另一個對象。此對象上的任何調用也需要被視爲從超時角度更新最後訪問時間。這可能很快會與多個嵌套對象相當複雜。但這只是一個假設的問題,也許是YAGNI;但我想知道是否有什麼辦法可以實現。

編輯:(因爲這些點沒有在原來的問題提到的)

  1. Session類確實有一個rollback方法。我只是沒有添加它來保持代碼小!
  2. 商店實際上在數據庫事務範圍內轉到後端數據庫。因此,這個類中的所有Store調用實際上都會將數據寫入數據庫,但只有在調用了會話提交後才需要提交數據庫。
+0

那麼,這個類的用法看起來有點奇怪。這實際上意味着您的應用程序在某個時刻必然會得到異常,因爲它無法檢查「會話」是否仍然存在。你究竟在努力完成什麼? [具有過期策略的緩存](http://msdn.microsoft.com/zh-cn/library/system.runtime.caching.memorycache.aspx)(.NET 4)? – Groo

+0

@ Groo,在創建類的對象並調用commit方法之後,如果對象的用戶不在對象上調用大於或等於超時的任何方法,那麼只會引發異常。否則,不會拋出異常,最終用戶會調用Commit並完成它。 – Santhosh

+2

真正的生活「用戶」還是其他任何代碼?不應該在UI中執行/檢查嗎? – Deanna

回答

2

在別的之前,你應該考慮反思你的會話對象應該負責什麼。通常,當我看到Commit方法時,我也會尋找Rollback方法,以確保如果操作失敗(雖然我仍不確定該類應該做什麼),那麼更新在某種方式上是一致的。另外,如果Commit提交您的StoreSomething方法添加的瞬態數據,那麼我不明白爲什麼應該打開「會話」(不管是什麼),直到您決定實際提交。

爲問題添加更好的描述和一些背景可能使我們能夠長期提供更好的解決方案。

說了這麼多,稍微重構後的版本可能是:

  1. 開始先定義一個接口(Liskov Substitution Principle):

    public interface IMySession 
    { 
        void StoreName(string name); 
        void StoreAddress(string address); 
        void Commit(); 
    } 
    
  2. 實現一個簡單的「普通老式「具有基本功能的會話(Single Responsibility Principle):

    public class BasicSession : IMySession 
    { 
        #region IMySession members 
    
        public void StoreName(string name) 
        { 
         // plain store 
        } 
    
        public void StoreAddress(string address) 
        { 
         // plain store 
        } 
    
        public void Commit() 
        { 
         // plain commit 
        } 
    
        #endregion 
    } 
    
  3. 最後,創建一個代理類,它檢查超時和轉發方法調用基類:

    public class TimeLimitedSessionProxy : IMySession 
    { 
        private readonly IMySession _baseSession; 
        private readonly TimeSpan _timeout; 
        private DateTime _lastAccessedTime = DateTime.Now; 
    
        public TimeLimitedSessionProxy(IMySession baseSession, TimeSpan timeout) 
        { 
         _baseSession = baseSession; 
         _timeout = timeout; 
        } 
    
        #region IMySession members 
    
        public void StoreName(string name) 
        { 
         IfNotTimedOut(() => _baseSession.StoreName(name)); 
        } 
    
        public void StoreAddress(string address) 
        { 
         IfNotTimedOut(() => _baseSession.StoreAddress(address)); 
        } 
    
        public void Commit() 
        { 
         IfNotTimedOut(() => _baseSession.Commit()); 
        } 
    
        #endregion 
    
        private void IfNotTimedOut(Action action) 
        { 
         if (DateTime.Now - _lastAccessedTime > _timeout) 
         { 
          throw new TimeoutException("session timed out"); 
         } 
    
         action(); 
    
         _lastAccessedTime = DateTime.Now; 
        } 
    } 
    

總體結果:

  • 你的代碼的其他部分應該接受一個IMySession對象,而不是關心它是如何交流的在引擎蓋下實施。

  • 即使是TimeLimitedSessionProxy也接受IMySession並且對實際的實現無知;所有關心的是時機。

  • 如果您決定添加其他功能,請考慮將這些類完好保留,並根據需要保留proxyingdecorating

+0

@ Groo,我在問題的最後添加了一個編輯,以進一步澄清問題。但是,您的解決方案確實提供了相當不錯的重構。 – Santhosh