簡體   English   中英

如何有效地同步列表和枚舉?

[英]How to synchronize a list and an enumerable in an effective way?

我經常遇到這樣的問題,我需要在C#中同步兩個列表。 例如,我有一個簡單的字符串數組。 我想以非常簡單的方式將這些字符串加載到Listview的Items列表中。 我還想以最少的項目交換來更新listview。

例:

 var strings = new List<string>() { "a", "b", "c", "d" };
 listview1.Items.Synchronize(strings);
 strings.Add("xx");
 listview1.Items.Synchronize(strings); // just create a new item for xx

我這里有一個簡短的擴展功能,它可以將兩個具有不同類型的列表同步。 Lambda擴展功能執行轉換。 用法示例:

        listView1.Items.SyncList(strings, lvItem => lvItem.Tag as string, str => new ListViewItem(str) { Tag = str });

擴展功能定義如下:

    /// <summary>
    /// synchronizes an enumerable with a list with two different types, 
    /// </summary>
    /// <typeparam name="TSource">Type of the elements in the source list</typeparam>
    /// <typeparam name="TDestination">Type of the elements in the destination list</typeparam>
    /// <param name="source">Source</param>
    /// <param name="destination">Destination list</param>
    /// <param name="selector">returns the corresponding source object for the destination list item</param>
    /// <param name="creator">Creates new object for the destination list from the source. The selection function applied on the new object must return the source object. </param>
    public static void SyncList<TSource, TDestination>(this IList destination, IEnumerable<TSource> source, Func<TDestination, TSource> selector, Func<TSource, TDestination> creator)
        where TDestination : class
        where TSource : class
    {
        if (source == null)
            throw new ArgumentNullException("source");

        if (destination == null)
            throw new ArgumentNullException("destination");

        if (selector == null)
            throw new ArgumentNullException("selector");

        if (creator == null)
            throw new ArgumentNullException("creator");

        var syncObject = destination.IsSynchronized ? destination.SyncRoot : new object();

        lock (syncObject)
        {
            var ExistingItems = destination.OfType<TDestination>().Where(d => selector(d) != null).ToDictionary(d => selector(d));

            foreach (var s in source)
            {
                if (!ExistingItems.Remove(s)) // s does not exist yet in the destination list
                {
                    var NewObject = creator(s);

                    if (selector(NewObject) != s)
                        throw new ArgumentException("the selector must return the creation object of the new item");

                    destination.Add(creator(s));
                }
            }

            var RemovedItems = ExistingItems.Values;

            if (RemovedItems.Count == destination.Count)
                destination.Clear();
            else
                foreach (var i in RemovedItems)
                {
                    destination.Remove(i);
                }

        }

    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM