PCL配置文件78中System.Threading.Timer的问题 - 警告

时间:2014-03-24 20:27:26

标签: c# android xamarin mvvmcross portable-class-library

我很惊讶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)

如何正确摆脱这些警告?

3 个答案:

答案 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。