2014-03-24 52 views
3

我很驚訝配置文件78庫中不存在方便的System.Threading.Timer類。要使用這個類我創建了另一個PCL它的目標4.0框架和周圍寫了一個簡單的包裝(因爲它是在一個博客文章建議):System.Threading.Timer在PCL配置文件78中的問題 - 警告

public class PCLTimer 
{ 
    private Timer timer; 
    private Action<object> action; 

    public PCLTimer (Action<object> action, object state, int dueTimeMilliseconds, int periodMilliseconds) 
    { 
     this.action = action; 
     timer = new Timer (PCLTimerCallback, state, dueTimeMilliseconds, periodMilliseconds); 
    } 

    private void PCLTimerCallback (object state) 
    { 
     action.Invoke (state); 
    } 

    public bool Change (int dueTimeMilliseconds, int periodMilliseconds) 
    { 
     return timer.Change (dueTimeMilliseconds, periodMilliseconds); 
    } 
} 

現在我可以在主PCL庫中引用這個4.0庫,並使用PCLTimer 。但是,當我嘗試建立我的主要的Android項目,我得到以下警告:

Warning CS1684: Reference to type 'System.Threading.Timer' claims it is defined in 'c:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETPortable\v4.5\Profile\Profile78\mscorlib.dll', but it could not be found (CS1684) (Prototype.Core) 

Warning MSB3247: Found conflicts between different versions of the same dependent assembly. (MSB3247) (Prototype.Droid) 

如何擺脫這些警告正確的?

+0

請參閱http://stackoverflow.com/questions/12555049/timer-in-便攜式圖書館 - 包括來自PCL團隊的更新ms – Stuart

+0

是的,我看到了這個問題,並從公認的答案中實現了第三種解決方案。現在我正在詢問這些警告。關於修復4.5.1 PCL庫的問題 - Xamarin工作室還沒有提供或者什麼?我的意思是我不能引用Timer,它不存在於我的PCL中的System.Threading命名空間中。 –

+1

我建議不要使用只插入.NET 4.0 Timer的答案,而是使用Task.Delay構建自己的計時器類,如http://stackoverflow.com/a/21095323/957673中所述。這避免了完全引用System.Threading.Timer的問題。 – Bognar

回答

3

您是否需要將綁定添加到app.config?當我添加一個WP8項目時,我不得不爲HttpClient做類似的事情。

<?xml version="1.0" encoding="utf-8"?> 
<configuration> 
    <runtime> 
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> 
     <dependentAssembly> 
     <assemblyIdentity name="System.Net.Http" 
          publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> 
     <bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="2.0.5.0" /> 
     </dependentAssembly> 
    </assemblyBinding> 
    </runtime> 
</configuration> 
+0

我試圖做這樣的事情,但它沒有幫助。很明顯,我有一些問題與mscorlib.dll。有兩個 - 一個是4.5 PCL,另一個是4.0 PCL。我需要弄清楚如何消除歧義。 –

1

而不是把定時器封裝實現到一個單獨的.NET 4.0的項目,我已經解決了這個問題以不同的方式:

我創建的核心項目的ITimerWrapper接口,並把sepearate實現在Droid和WinPhone項目。然後,我使用IoC在應用程序啓動時設置所需的實現。

使用此方法的Timer的不同版本的PCL之間沒有衝突。

另一個優點是我現在可以在WinPhone項目中使用DispatcherTimers - 當我在Android和WinPhone之間共享代碼時,我只能使用System.Threading.Timers。

+0

我喜歡這個解決方案:) –

4

這裏是一個完全重新實現Timer類在檔案78暫時消失的,採用異步任務:

using System; 
using System.Threading; 
using System.Threading.Tasks; 

namespace Quantum 
{ 
    public delegate void TimerCallback(object state); 

    public sealed class Timer : IDisposable 
    { 
     private static Task CompletedTask = Task.FromResult(false); 

     private TimerCallback Callback; 
     private Task Delay; 
     private bool Disposed; 
     private int Period; 
     private object State; 
     private CancellationTokenSource TokenSource; 

     public Timer(TimerCallback callback, object state, int dueTime, int period) 
     { 
      Callback = callback; 
      State = state; 
      Period = period; 
      Reset(dueTime); 
     } 

     public Timer(TimerCallback callback, object state, TimeSpan dueTime, TimeSpan period) 
      : this(callback, state, (int)dueTime.TotalMilliseconds, (int)period.TotalMilliseconds) 
     { 
     } 

     ~Timer() 
     { 
      Dispose(false); 
     } 

     public void Dispose() 
     { 
      Dispose(true); 
      GC.SuppressFinalize(this); 
     } 

     private void Dispose(bool cleanUpManagedObjects) 
     { 
      if (cleanUpManagedObjects) 
       Cancel(); 
      Disposed = true; 
     } 

     public void Change(int dueTime, int period) 
     { 
      Period = period; 
      Reset(dueTime); 
     } 

     public void Change(TimeSpan dueTime, TimeSpan period) 
     { 
      Change((int)dueTime.TotalMilliseconds, (int)period.TotalMilliseconds); 
     } 

     private void Reset(int due) 
     { 
      Cancel(); 
      if (due >= 0) 
      { 
       TokenSource = new CancellationTokenSource(); 
       Action tick = null; 
       tick =() => 
       { 
        Task.Run(() => Callback(State)); 
        if (!Disposed && Period >= 0) 
        { 
         if (Period > 0) 
          Delay = Task.Delay(Period, TokenSource.Token); 
         else 
          Delay = CompletedTask; 
         Delay.ContinueWith(t => tick(), TokenSource.Token); 
        } 
       }; 
       if (due > 0) 
        Delay = Task.Delay(due, TokenSource.Token); 
       else 
        Delay = CompletedTask; 
       Delay.ContinueWith(t => tick(), TokenSource.Token); 
      } 
     } 

     private void Cancel() 
     { 
      if (TokenSource != null) 
      { 
       TokenSource.Cancel(); 
       TokenSource.Dispose(); 
       TokenSource = null; 
      } 
     } 
    } 
}