将一个集合投射到另一个集合并保持同步

时间:2015-09-30 11:09:10

标签: c# collections

我经常要将一个集合投射到另一个集合中。使用从linq到对象的Select运算符非常容易:

var targetCollection = sourceCollection.Select(source => new Target
{ 
   Source = source,
   //some other stuff here
}

但我必须让收藏最终保持同步。在sourceCollection中添加或删除新项目时,更改必须反映在targetCollection中。我必须做这样的事情:

void OnSourceCollectionChanged(){
   SyncCollections(sourceCollection, targetCollection)
}

void SyncCollections(ICollection<Source> sourceCollection, ICollection<Target> targetCollection)
{
   //find items that are no longer present
   var newItems = sourceCollection.Where(s => !targetCollection.Any(t => t.Source == s));
   //find items that were added
   var oldItems = targetCollection.Where(t => !sourceCollection.Any(s => t.Source == s));

   foreach(var oldItem in oldItems)  targetCollection.Remove(oldItem);

   foreach(var source in newItems){
       var target = new Target{ Source = source };
       targetCollection.Add(target);
   }
}

我相信已经有很好的图书馆来处理这种情况。你能推荐我一些吗?

我想到API,我只是指定投影,也许是“等式比较器”来比较源项目和目标项目:

var synchronizer = new CollectionSynchronizer<Source, Target>(
    source => new Target
    {
        Source = source
    });

synchronizer.Sync(sourceCollection, targetCollection);

//or specify filter as well:
synchronizer.Sync(
    sourceCollection.Where(s => s.Created > DatTime.Now.AddMinutes(-5)),
    targetCollection);

2 个答案:

答案 0 :(得分:0)

您可以使用ObservableCollection

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;

public class Program
{
    public static void Main()
    {
        var observableList = new ObservableCollection<string>();
        var syncList = new List<string>(observableList);

        observableList.CollectionChanged += (o,e) => { 
            foreach (var item in e.NewItems){
                syncList.Add((string)item);
            }
        };

        observableList.Add("Test");
        Console.WriteLine(syncList[0]);
    }
}

答案 1 :(得分:0)

如果您的源集合实现了INotifyCollectionChanged并且是IEnumerable(例如ObservableCollection),您可以执行包装器集合。

INotifyCollectionChanged

它还可以实现CollectionChanged。在这种情况下,您必须使用OnSourceCollectionChanged方法中的适当参数提升WITH CTE2 AS ( SELECT * FROM (SELECT ID,HEAD,FACE,THOR,ABDO,SPINE FROM PARTSDATA) T UNPIVOT ( QUANTITY FOR PART IN (HEAD,FACE,THOR ,ABDO , SPINE) ) AS U ), CTE3 AS ( SELECT RANK() OVER(PARTITION BY ID ORDER BY QUANTITY DESC) AS RN,QUANTITY,PART,ID FROM CTE2 ) SELECT DISTINCT C1.ID,STUFF(DT.CONTENT,1,1,'') AS [AREA INJURED] FROM CTE3 C1 CROSS APPLY(SELECT ','+PART FROM CTE3 WHERE ID = C1.ID AND RN=1 FOR XML PATH(''))DT(CONTENT) WHERE RN=1 事件。

您还可以创建内部List集合并公开它。在这种情况下,代理集合将具有与源集合相同的索引的代理。这取决于您的需求。