我很惊讶Profile 78库中不存在方便的System.Threading.Timer类。为了使用这个类,我创建了另一个针对4.0框架的PCL,并编写了一个简单的包装器(正如一篇博文中所建议的那样):
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);
}
}
现在我可以参考这个4.0库并在主PCL库中使用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 :(得分:4)
这是使用异步任务暂时消失在Profile 78中的Timer类的完全重新实现:
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;
}
}
}
}
答案 1 :(得分: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>
答案 2 :(得分:1)
我没有将Timer包装器实现放入单独的.net 4.0项目中,而是以不同的方式解决了这个问题:
我在核心项目中创建了一个ITimerWrapper接口,并在Droid和WinPhone项目中实现了单独的实现。然后我使用IoC在app start设置所需的实现。
使用此方法的不同PCL版本的Timer之间没有冲突。
另一个优点是我现在可以在WinPhone项目中使用DispatcherTimers - 当我在Android和WinPhone之间共享代码时,我只能使用System.Threading.Timers。