C# 如何有效地同步列表和可枚举项?

C# 如何有效地同步列表和可枚举项?,c#,list,lambda,enumerable,C#,List,Lambda,Enumerable,我经常遇到这样的问题,我需要在C#中同步两个列表。 例如,我有一个简单的字符串数组。 我想以一种非常简单的方式将这些字符串加载到Listview的Items列表中。我还想用最少的项目交换来更新listview 例如: var strings = new List<string>() { "a", "b", "c", "d" }; listview1.Items.Synchronize(strings); strings.Add("xx"); listview1.Items.S

我经常遇到这样的问题,我需要在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
var strings=newlist(){“a”、“b”、“c”、“d”};
listview1.Items.Synchronize(字符串);
字符串。添加(“xx”);
listview1.Items.Synchronize(字符串);//只需为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);
                }

        }

    }
//
///将可枚举项与具有两种不同类型的列表同步,
/// 
///源列表中元素的类型
///目标列表中元素的类型
///来源
///目的地列表
///返回目标列表项对应的源对象
///从源为目标列表创建新对象。应用于新对象的选择函数必须返回源对象。
公共静态void SyncList(此IList目标、IEnumerable源、Func选择器、Func创建者)
目的地:班级
where TSource:class
{
if(source==null)
抛出新的ArgumentNullException(“源”);
如果(目标==null)
抛出新的ArgumentNullException(“目标”);
if(选择器==null)
抛出新的ArgumentNullException(“选择器”);
如果(创建者==null)
抛出新的ArgumentNullException(“创建者”);
var syncObject=destination.IsSynchronized?destination.SyncRoot:新对象();
锁定(同步对象)
{
var ExistingItems=destination.OfType()。其中(d=>selector(d)!=null)。ToDictionary(d=>selector(d));
foreach(源中的var s)
{
如果目标列表中尚不存在(!ExistingItems.Remove(s))//s
{
var NewObject=创建者;
if(选择器(新对象)!=s)
抛出新ArgumentException(“选择器必须返回新项的创建对象”);
目的地。添加(创建者);
}
}
var RemovedItems=现有项。值;
if(RemovedItems.Count==目的地.Count)
destination.Clear();
其他的
foreach(移除项目中的var i)
{
目的地。删除(i);
}
}
}