为什么Lookup在C#中是不可变的?

Dictionary不同,您无法通过逐个添加元素来构建Lookup 。 你碰巧知道原因吗?

Lookup就像C ++中的multimap一样; 为什么我们不能在C#中修改它? 如果我们真的不能,我们如何在C#中构建multimap数据结构?

LookupILookup作为LINQ的一部分引入,LINQ通常比框架的其他方面采用更多function方法。 我个人喜欢 Lookup (至少是公开的)不可变的事实 – 我期待更多不可变的集合可用 。

如果要创建自己的多图数据结构,只需维护一个Dictionary>或类似的东西。 您可能需要查看我的Edulinq Lookup实现以获取一些示例代码。

这是我写的一个实现

 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; public class MultiLookup : ILookup { Dictionary> Contents = new Dictionary>(); public void Add(Key key, Value value) { if (!Contains(key)) { Contents[key]=new HashSet(); } Contents[key].Add(value); } public void Add(IEnumerable> items) { foreach (var item in items) { Add(item.Item1, item.Item2); } } public void Remove(Key key, Value value) { if (!Contains(key)) { return; } Contents[key].Remove(value); if (Contents[key].Count==0) { Contents.Remove(key); } } public void RemoveKey(Key key) { Contents.Remove(key); } public IEnumerable Keys { get { return Contents.Keys; } } public int Count { get { return Contents.Count; } } public bool Contains(Key key) { return Contents.ContainsKey(key); } private class Grouping : IGrouping { public MultiLookup _source; public Key _key; public Key Key { get { return _key; } } public static HashSet Empty = new HashSet(); public IEnumerator GetEnumerator() { if (!_source.Contains(_key)) { yield break; } else { foreach (var item in _source[_key]) { yield return item; } } } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return this.GetEnumerator(); } } public IEnumerator> GetEnumerator() { return (from p in Contents select new Grouping() { _key = p.Key, _source = this }).GetEnumerator(); } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return this.GetEnumerator(); } public IEnumerable this[Key key] { get { return Contents[key]; } } } 

和一个测试用例(可能不是详尽无遗)

 using FluentAssertions; using System.Linq; using Xunit; public class MultiLookupSpec { MultiLookup Fixture = new MultiLookup(); [Fact] public void NewLookupShouldBeEmpty() { Fixture.Count.Should().Be(0); } [Fact] public void AddingANewValueToANonExistentKeyShouldCreateKeyAndAddValue() { Fixture.Add(0, "hello"); Fixture.Count.Should().Be(1); } [Fact] public void AddingMultipleValuesToAKeyShouldGenerateMultipleValues() { Fixture.Add(0, "hello"); Fixture.Add(0, "cat"); Fixture.Add(0, "dog"); Fixture[0].Should().BeEquivalentTo(new []{"hello", "cat", "dog"}); } [Fact] public void RemovingAllElementsOfKeyWillAlsoRemoveKey() { Fixture.Add(0, "hello"); Fixture.Add(0, "cat"); Fixture.Add(0, "dog"); Fixture.Remove(0, "dog"); Fixture.Remove(0, "cat"); Fixture.Remove(0, "hello"); Fixture.Contains(0).Should().Be(false); } [Fact] public void EnumerationShouldWork() { Fixture.Add(0, "hello"); Fixture.Add(0, "cat"); Fixture.Add(0, "dog"); Fixture.Add(1, "house"); Fixture.Add(2, "pool"); Fixture.Add(2, "office"); Fixture.Select(s => s.Key).Should().Contain(new[] { 0, 1, 2 }); Fixture.SelectMany(s => s).Should().Contain(new[] { "hello", "cat", "dog", "house", "pool", "office" }); } } 

我有同样的问题和疑问。 为什么Lookup是不可变的? 我用IDictionary的一些扩展方法解决了它

 public static void Add(this IDictionary dict,TKey key,TItem item) where TList : ICollection,new() { if(!dict.ContainsKey(key)) { dict.Add(key, new TList()); } dict[key].Add(item); } public static void Remove(this IDictionary dict, TKey key) where TList : IEnumerable, new() { if (dict.ContainsKey(key)) { dict.Remove(key); } } public static TList Items(this IDictionary dict, TKey key) where TList : IEnumerable, new() { if (dict.ContainsKey(key)) { return dict[key]; } return default(TList); }