可移植类库中的ConcurrentBag替代方案

时间:2014-04-28 16:55:49

标签: c# .net multithreading portable-class-library

我有一个应用程序,其中包含存储在static ConcurrentBag

中的对象列表

UI有一个计时器,可以运行可以更新ConcurrentBag中的对象的方法。

只有一个线程(由计时器启动)将尝试更新这些对象。但是,此线程将枚举列表,然后在项目进行时更新。

同时,UI线程可以读取这些对象。

ConcurrentBag正在为我想做的事情做得很好。所有业务逻辑都在一个单独的项目中,我现在需要将所有内容移植到iOS和Android。我正在使用Xamarin进行此操作,因此将业务逻辑转换为可移植类库

虽然我定位的所有内容似乎都支持ConcurrentBag,但当我尝试在 PCL 中访问它时,System.Collections.Concurrent不可用。即使我只针对.net 4.5及以上版本+ windows存储应用程序(两者都使用了ConcurrentBags

是否有ConcurrentBag的另一种选择,或者我最好只为每个目标系统创建单独的项目?

1 个答案:

答案 0 :(得分:1)

好吧,如果显而易见的不行,那么你有几个选择。首先,是反编译ConcurrentBag并使用该代码。第二,是想出一个替代品。我估计你在特定情况下不一定需要ConcurrentBag的性能保证和订购问题......所以,这是适合你的账单的一个有效例子:

namespace Naive
{
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;

    public class ThreadSafeCollectionNaive<T>
    {
        private readonly List<T> _list = new List<T>();
        private readonly object _criticalSection = new object();

        /// <summary>
        /// This is consumed in the UI. This is O(N)
        /// </summary>
        public ReadOnlyCollection<T> GetContentsCopy()
        {
            lock (_criticalSection)
            {
                return new List<T>(_list).AsReadOnly();
            }
        }

        /// <summary>
        /// This is a hacky way to handle updates, don't want to write lots of code
        /// </summary>
        public void Update(Action<List<T>> workToDoInTheList)
        {
            if (workToDoInTheList == null) throw new ArgumentNullException("workToDoInTheList");

            lock (_criticalSection)
            {
                workToDoInTheList.Invoke(_list);
            }
        }

        public int Count
        {
            get
            {
                lock (_criticalSection)
                {
                    return _list.Count;
                }
            }
        }

        // Add more members as you see fit
    }

    class Program
    {
        static void Main(string[] args)
        {
            var collectionNaive = new ThreadSafeCollectionNaive<string>();

            collectionNaive.Update((l) => l.AddRange(new []{"1", "2", "3"}));

            collectionNaive.Update((l) =>
                                       {
                                           for (int i = 0; i < l.Count; i++)
                                           {
                                               if (l[i] == "1")
                                               {
                                                   l[i] = "15";
                                               }
                                           }
                                       });
        }
    }
}