什么是集合语义(在.NET)?语义、NET

2023-09-02 10:33:06 作者:你爱的人会爱你

我需要保持集合语义在我自己的类。你能不能解释一下,什么是集合语义?据我了解,这是一组必须在一个类中实现一些接口。是真的吗?而如果是 - 什么正是我必须在类实现和为什么?这些是两个接口 - 的ICollection和IEnumerable - 足够,或者这些仅仅是最必要的呢?

I need to maintain collection semantics in my own class. Couldn't you explain, what is the collection semantics? As I understand, it is a set of some interfaces that must be implemented in a class. Is it true? And if yes – what exactly must I implement in the class and why? Are these two interfaces – ICollection and IEnumerable – enough, or these are only the most necessary ones?

我编程使用这是一个循环链表文章,为帮助。

推荐答案

有.NET中许多集合类型,它们都具有一些共同的行为,例如:

There are many collection types in .NET, and they all share some common behavior, for instance:

您可以用一一列举的foreach 他们有一个计数属性 您可以添加使用项目添加方法 等等... You can enumerate them using foreach They have a Count property You can add items using the Add method etc...

此行​​为是从集合类型预期,你猜对了正确的:这一切都在的ICollection< T> 接口。让我们来看看接口层次:

This behavior is expected from a collection type, and you guessed it right: it's all in the ICollection<T> interface. Let's take a look at the interface hierarchy:

的IEnumerable&LT; T&GT; 让你的类与枚举的foreach 的ICollection&LT; T&GT; 的IEnumerable&LT; T&GT; 的再presents集合: 允许检索项目计数 您的可能的能添加 / 删除 / 清除从集合项 的集合,可以只读的,在这种情况下,的IsReadOnly 应该返回 还有几个其他的辅助方法太:包含 / CopyTo从IEnumerable<T> allows your class to be enumerated with foreach ICollection<T> is an IEnumerable<T> that represents a collection: it allows to retrieve the item Count you possibly can Add/Remove/Clear items from the collection a collection could be read only, in that case IsReadOnly should return true There's a couple other helper methods too: Contains/CopyTo. 在它增加了一个索引 在一些指数相关的功能:插入 / RemoveAt 的IndexOf It adds an indexer some index-related functions: Insert/RemoveAt IndexOf

哪个接口应实现是一个原则问题的语义

Which interface you should implement is a matter of semantics:

的IEnumerable&LT; T&GT; 只是一个枚举的序的。它只能通过消耗code一旦列举,因为你永远不知道它是如何可能表现在多个枚举。像ReSharper的工具,甚至会发出警告,如果你列举了的IEnumerable&LT; T&GT; 多次 当然,大部分的时间你可以放心地列举它多次,但有些时候,你不应该。例如,枚举可以执行一个SQL查询(LINQ的思考到SQL为例)。

IEnumerable<T> is just an enumerable sequence. It should only be enumerated once by consuming code, because you never know how it may behave on multiple enumerations. Tools like ReSharper will even emit warnings if you enumerate an IEnumerable<T> multiple times. Sure, most of the time you can safely enumerate it multiple times but there are times when you shouldn't. For instance, an enumeration could execute a SQL query (think Linq-to-SQL for instance).

您实施的IEnumerable&LT; T&GT; 定义一个函数:的GetEnumerator 返回连接 IEnumerator的&LT; T&GT; 。枚举器是一个对象,它是一种指针在你的序列的当前元素。它可以返回该当前的价值,它可以移动到下一个元素的MoveNext 。这也是一次性的(和它的配置在枚举的结束由的foreach )。

You implement an IEnumerable<T> by defining one function: GetEnumerator which returns en IEnumerator<T>. An enumerator is an object that is a kind of pointer to a current element in your sequence. It can return this Current value, and it can move to the next element with MoveNext. It's also disposable (and it's disposed at the end of the enumeration by foreach).

让我们分解一个的foreach 循环:

IEnumerable<T> sequence = ... // Whatever
foreach (T item in sequence)
    DoSomething(item);

这是等同于以下内容:

IEnumerator<T> enumerator = null;
try
{
    enumerator = sequence.GetEnumerator();
    while (enumerator.MoveNext())
    {
        T item = enumerator.Current;
        DoSomething(item);
    }
}
finally
{
    if (enumerator != null)
        enumerator.Dispose();
}

有关记录,实施的IEnumerable 要求不严格,使一类可用以的foreach 。鸭打字就足够了这里,但我题外话太多。

For the record, implementing IEnumerable is not strictly required to make a class usable with a foreach. Duck typing is sufficient here but I'm digressing way too much.

当然,你可以轻松地与产量实现该模式关键字:

And of course you can implement the pattern easily with the yield keyword:

public static IEnumerable<int> GetAnswer()
{
    yield return 42;
}

这将创建一个将实施的IEnumerable℃的私有类; INT&GT; 给你,让你不必

This will create a private class which will implement IEnumerable<int> for you so you don't have to.

的ICollection&LT; T&GT; 再presents集合,它是安全的枚举多次。但是,你真的不知道什么样的收藏它吧。这可能是一个集合,列表,字典,等等。

ICollection<T> represents a collection, which is safely enumerable multiple times. But you don't really know what kind of collection it it. It could be a set, a list, a dictionary, whatever.

这是集合语义。

一些例子:

T [] - 它实现的ICollection&LT; T&GT; 即使你不能添加 / 删除 名单,其中,T&GT; 的HashSet&LT; T&GT; - 集合的一个很好的例子,但不是列表 词典&LT; TKEY的,TValue&GT; - 是的,这是一个的ICollection&LT; KeyValuePair&LT; TKEY的,TValue&GT;&GT; 的LinkedList&LT; T&GT; 的ObservableCollection&LT; T&GT; T[] - it implements ICollection<T> even if you can't Add/Remove List<T> HashSet<T> - a good example of a collection but not a list Dictionary<TKey, TValue> - yes, that's an ICollection<KeyValuePair<TKey, TValue>> LinkedList<T> ObservableCollection<T>

的IList&LT; T&GT; 让你知道的集合,可以让你通过索引访问元素很容易(即在 O(1)的时间)。

这是不是你的循环链表的情况下,因为它不仅需要的 O(N)的时间,但有摆在首位没有任何意义的指标。

This is not the case for your circular linked list, as not only it would need O(n) time, but there's no meaningful index in the first place.

一些例子:

T [] 名单,其中,T&GT; 的ObservableCollection&LT; T&GT; T[] List<T> ObservableCollection<T>

注意的HashSet&LT; T&GT; 词典&LT; TKEY的,TValue&GT; 不再列表中的实例。这些都不是列表。 的LinkedList&LT; T&GT; 在语义上的列表,但它并没有提供在的通过索引访问O(1)的时间(它需要的为O(n)的)。

Notice that HashSet<T> and Dictionary<TKey, TValue> are no longer in the list for instance. These are not lists. LinkedList<T> is semantically a list, but it doesn't offer access by index in O(1) time (it requires O(n)).

我应该说还有读,使得在进入.NET 4.5只当量: IReadOnlyCollection&LT;出T&GT; IReadOnlyList&LT;出T&GT; 。这些都是很好的为他们提供的协方差。

I should mention there are read only equivalents that made in into .NET 4.5: IReadOnlyCollection<out T>, IReadOnlyList<out T>. These are nice for the covariance they provide.