对KeyedCollection中的键使用int可以吗

本文关键字:int KeyedCollection | 更新日期: 2023-09-27 17:47:25

我经常需要一个具有数字标识符的非顺序对象的集合。我喜欢使用KeyedCollection,但我认为有一个严重的缺点。如果使用int作为键,则无法再通过索引访问集合的成员(collection[index]现在实际上是collection[key])。这是一个严重到可以避免使用int作为键的问题吗?更可取的替代方案是什么?(可能是int.ToString()?)

我以前这样做过,没有遇到任何重大问题,但最近我遇到了一个严重的问题,即如果密钥是int,那么针对KeyedCollection的XML序列化就不能工作

基本上,您需要决定类的用户是否可能被他们不能做的事实所混淆,例如:

for(int i=0; i=< myCollection.Count; i++)
{
    ... myCollection[i] ...
}

尽管他们当然可以使用foreach,或者使用cast:

for(int i=0; i=< myCollection.Count; i++)
{
    ... ((Collection<MyType>)myCollection)[i] ...
}

这不是一个容易的决定,因为它很容易导致黑森伯格。我决定在我的一个应用程序中允许它,该类用户的访问几乎完全是通过密钥进行的。

不过,我不确定我是否会对共享类库这样做:一般来说,我会避免在公共API中公开KeyedCollection:相反,我会公开IList<T>在公共API中,并且需要密钥访问的API的消费者可以使用采用IEnumerable<TItem>并用它填充集合。这意味着您可以轻松地从API检索的列表中构建新的KeyedCollection。

关于序列化,我向Microsoft Connect报告了一个性能问题:KeyedCollection维护一个内部字典和一个列表,并对两者进行序列化-序列化列表就足够了,因为在反序列化时可以很容易地重新创建字典。

由于这个原因以及XmlSerialization错误,我建议您避免序列化KeyedCollection,而只序列化KeyedCollection.Items列表。

我不喜欢用另一种类型包装int键的建议。在我看来,简单地添加复杂性以使类型可以用作KeyedCollection中的项是错误的。我会使用字符串键(ToString)而不是这样做——这很像VB6 Collection类。

FWIW,我不久前在MSDN论坛上问了同样的问题。FxCop团队的一名成员做出了回应,但没有结论性的指导方针。

对KeyedCollection中的键使用int可以吗

一个简单的解决方案可能是将int封装到另一个类型中,以创建一个不同的类型来解决过载问题。如果你使用struct,这个包装器没有任何额外的开销:

struct Id {
    public int Value;
    public Id(int value) { Value = value; }
    override int GetHashCode() { return Value.GetHashCode(); }
    // … Equals method.
}

最好将GetById(int)方法添加到集合类型中。如果您不需要任何其他密钥来访问包含的对象,则可以使用Collection<T>

public class FooCollection : Collection<Foo>
 { Dictionary<int,Foo> dict = new Dictionary<int,Foo>();
   public Foo GetById(int id) { return dict[id]; }
   public bool Contains(int id) { return  dict.Containskey(id);}
   protected override void InsertItem(Foo f)
    { dict[f.Id] = f;
      base.InsertItem(f);
    }
   protected override void ClearItems()
    { dict.Clear();
      base.ClearItems();
    }
   protected override void RemoveItem(int index)
    { dict.Remove(base.Items[index].Id);
      base.RemoveItem(index);
    }
   protected override void SetItem(int index, Foo item)
    { dict.Remove(base.Items[index].Id);
      dict[item.Id] = item;
      base.SetItem(index, item);
    }
 }




 }

KeyedCollection中的键应该是唯一的,并且可以从所收集的对象快速派生。例如,给定一个person类,它可以是SSN属性,甚至可以连接FirstName和LastName属性(如果结果是唯一的)。如果ID合法地是正在收集的对象的字段,那么它就是密钥的有效候选者。但也许可以试着把它当作一根绳子来避免碰撞。