Runtime: 请添加接口 IReadOnlySet 并使 HashSet、SortedSet 实现它

创建于 2015-06-09  ·  104评论  ·  资料来源: dotnet/runtime

原来的

自从添加了IReadOnlyList后,集合和列表之间的奇偶性就下降了。 重新建立它会很棒。

使用它是一种与实现无关的说法:“这是这个只读集合,其中项目是唯一的”。

显然很多人都需要它:

SQL Server: https :
罗斯林: https :
评论中的一些人: http :

我在处理一个现实世界的问题时发现了这个讨论,我想使用字典的键集合进行只读集合操作。 为了支持这种情况,这里是我建议的 API。

编辑

基本原理

提议的API

 namespace System.Collections.Generic {
+    public interface IReadOnlySet<out T> : IReadOnlyCollection<T>, IEnumerable, IEnumerable<T> {
+        bool Contains(T value);
+        bool IsProperSubsetOf(IEnumerable<T> other);
+        bool IsProperSupersetOf(IEnumerable<T> other);
+        bool IsSubsetOf(IEnumerable<T> other);
+        bool IsSupersetOf(IEnumerable<T> other);
+        bool Overlaps(IEnumerable<T> other);
+        bool SetEquals(IEnumerable<T> other);
+    }
-    public class HashSet<T> : ICollection<T>, IDeserializationCallback, IEnumerable, IEnumerable<T>, IReadOnlyCollection<T>, ISerializable, ISet<T> {
+    public class HashSet<T> : ICollection<T>, IDeserializationCallback, IEnumerable, IEnumerable<T>, IReadOnlyCollection<T>, ISerializable, ISet<T>, IReadOnlySet<T> {
     }
-    public class SortedSet<T> : ICollection, ICollection<T>, IDeserializationCallback, IEnumerable, IEnumerable<T>, IReadOnlyCollection<T>, ISerializable, ISet<T> {
+    public class SortedSet<T> : ICollection, ICollection<T>, IDeserializationCallback, IEnumerable, IEnumerable<T>, IReadOnlyCollection<T>, ISerializable, ISet<T>, IReadOnlySet<T> {
     }
+    public class ReadOnlySet<T> : ICollection<T>, IEnumerable, IEnumerable<T>, IReadOnlyCollection<T>, IReadOnlySet<T>, ISet<T> {
+        public int Count { get; }
+        public ReadOnlySet(ISet<T> set);
+        public bool Contains(T value);
+        public bool IsProperSubsetOf(IEnumerable<T> other);
+        public bool IsProperSupersetOf(IEnumerable<T> other);
+        public bool IsSubsetOf(IEnumerable<T> other);
+        public bool IsSupersetOf(IEnumerable<T> other);
+        public bool Overlaps(IEnumerable<T> other);
+        public bool SetEquals(IEnumerable<T> other);
+    }
     public class Dictionary<TKey, TValue> {
-        public sealed class KeyCollection : ICollection, ICollection<TKey>, IEnumerable, IEnumerable<TKey>, IReadOnlyCollection<TKey> {
+        public sealed class KeyCollection : ICollection, ICollection<TKey>, IEnumerable, IEnumerable<TKey>, IReadOnlyCollection<TKey>, IReadOnlySet<TKey> {
+            public bool IsProperSubsetOf(IEnumerable<TKey> other);
+            public bool IsProperSupersetOf(IEnumerable<TKey> other);
+            public bool IsSubsetOf(IEnumerable<TKey> other);
+            public bool IsSupersetOf(IEnumerable<TKey> other);
+            public bool Overlaps(IEnumerable<TKey> other);
+            public bool SetEquals(IEnumerable<TKey> other);
         }
     }
 }

开放问题

  • 考虑到通常实例化的泛型类型的代码大小成本,将这些方法添加到Dictionary<TKey, TValue>.KeyCollection可以接受? 见这里
  • IReadOnlySet<T>应该在其他Dictionary KeyCollection例如SortedDictionaryImmutableDictionary

更新

  • 删除了TryGetValue因为它不在ISet<T> ,因此可能会阻止ISet<T>实现IReadOnlySet<T>
  • 添加ReadOnlySet<T>类似于ReadOnlyCollection<T> ReadOnlySet<T>类。
api-approved area-System.Collections up-for-grabs

最有用的评论

建议的 API 设计:

public interface IReadOnlySet<T> : IReadOnlyCollection<T> {    
    bool Contains(T item);
    bool IsSubsetOf(IEnumerable<T> other);
    bool IsSupersetOf(IEnumerable<T> other);
    bool IsProperSupersetOf(IEnumerable<T> other);
    bool IsProperSubsetOf(IEnumerable<T> other);
    bool Overlaps(IEnumerable<T> other);
    bool SetEquals(IEnumerable<T> other);
}

这是基于ISet<> API(显然变异方法除外)。

可惜Comparer不适合这个,但是ISet<>IReadOnlyDictionary<>公开比较器,所以现在修复为时已晚。

所有104条评论

如果我们只是有一些语言结构来使事物不可变,那不是很好吗? 那么我们就不必拥有这些神奇的接口了。

@whoisj哪种语言? CLR 有几十个。

即使作为潜在的语言功能,它也需要元数据表示。 对于这种情况,标记界面(或行为界面)与任何界面一样好。 试图通过新的元数据条目传达集合类型的不变性似乎并不合适,因为 CLR 不应该对任意类在内部如何运行做出假设(并且 CLR 根本没有集合类的概念)数组)。

@whoisj我认为这至少被考虑用于未来的 C# 版本之一。 但该决定不会影响所有集合对对称接口的需求。 此外,我可以想象可变项目的只读列表可能有用的场景,例如在关心代码质量和性能的游戏中。

不可变集合也已经可用:

https://msdn.microsoft.com/en-us/library/system.collections.immutable (v=vs.111).aspx

为了实现一个完全不可变的集合,我们只需要一种定义immutable T ,然后使用它来声明一个Immutable...<T>集合。

@HaloFour 之前我们一直在这条路上 : this )”。

@dsaf绝对! 在另一个问题中,我提议我们有一个可写的只读反术语,以启用可写元素的只读集合的​​使用。 类似于readonly Bag<writable Element>

我建议编译器将任何标有&引用视为不可变的。 我仍然觉得它只需要一个编译时检查,并且必须由 CLR 本身强制执行,因为我主要寻求逻辑的编译时验证而不是运行时保证。 这将涵盖开发人员希望不可变的任何引用,但以每次调用为基础。

@whoisj也许吧,但这是非常

您也将此视为编译器问题。 此时不涉及编译器(除了 JIT 编译器),只有验证器可以尝试防止执行“不正确”的代码。 如果跳过验证(或通过反射),即使是现有的不变性运行时机制, initonly字段,也很容易被破坏。

我确实同意,如果 C# 语言和编译器能够更好地支持“纯”方法,那就太好了。 属性PureAttribute已经存在,但它偶尔使用,并且确实没有任何语言支持。 即使 C# 确实通过编译器错误支持它(pure 只能调用 pure 等),但使用不同的语言也很容易打败它。 但是这些方法必须宣布自己并强制执行自己,因为一旦编译为 IL,所有赌注基本上都没有了,并且没有一个编译器可以改变现有程序集的执行方式。

@HaloFour公平。

假设我们没有支持“纯”或“常量”引用的通用方法,那么我认为建议是最好的选择。

如果您现在需要它,我的 Commons 库(Commons.Collections https://github.com/yanggujun/commonsfornet/tree/master/src/Commons.Collections/Set )具有只读集支持。 如果这被认为是广告,请管理员删除此帖子...我的建议是寻找一些开源实现。

@yanggujun感谢您的建议,这似乎是一个不错的库,但我会推出自己的库以避免额外的依赖。

我的建议是四处寻找一些开源实现。

这是一种变通方法,像 IReadOnlySet 这样的基本接口应该真正成为 .NET Framework 本身的一部分。

这是否需要一个 splet 才能“准备好进行 api 审查”?

当我们在做的时候,考虑给它命名与“只读”不同的东西(见有趣的帖子:http://stackoverflow.com/questions/15262981/why-does-listt-implement-ireadonlylistt-in-net-4- 5)
“可读”似乎没问题。

@GiottoVerducci不。即使不完美,我也希望保持一致的命名模式。 不过,您可以自由提出一个单独的问题来重命名现有接口。

建议的 API 设计:

public interface IReadOnlySet<T> : IReadOnlyCollection<T> {    
    bool Contains(T item);
    bool IsSubsetOf(IEnumerable<T> other);
    bool IsSupersetOf(IEnumerable<T> other);
    bool IsProperSupersetOf(IEnumerable<T> other);
    bool IsProperSubsetOf(IEnumerable<T> other);
    bool Overlaps(IEnumerable<T> other);
    bool SetEquals(IEnumerable<T> other);
}

这是基于ISet<> API(显然变异方法除外)。

可惜Comparer不适合这个,但是ISet<>IReadOnlyDictionary<>公开比较器,所以现在修复为时已晚。

    bool Contains(T item);

这不应该在IReadOnlyCollection<T>因为ICollection<T>Contains(T item)吗?

不可变集合包在仍处于测试阶段时已从 nuget 中取消列出。
我认为这是一个非常常见的用例,应该在标准库中处理。

正如标签所暗示的那样,这里的 API 是否还有更多工作要做? 如果它有帮助并且有人可以指出需要什么,我很高兴花一些时间在这上面。

提议的 API @ashmind看起来很棒。

可以让ISet<T>扩展IReadOnlySet<T>吗? 这没有发生IList<T> / IReadOnlyList<T>

如果没有,那么我想要考虑的其他更改是将IReadOnlySet<T>到 corefx 中所有ISet<T>实现的接口列表中,包括HashSet<T>SortedSet<T>和它们的System.Collections.Immutable不可变的对应物。

我必须同意@GiottoVerducci 。 使用IReadOnlySet<T>类的名称不会声明合同功能,而是声明合同限制。 然后将同一个合同与另一个与这些限制相矛盾的合同结合使用是令人困惑的。 我相信合同名称应该描述与实施者支持的内容有关的肯定断言。 诚然,像IReadableSet<T>这样的名字并不好,但它至少更好地描述了实现者的工作。

@HaloFour我原则上同意,但我们现在的情况与IReadOnlyList<T> 。 恕我直言,保持一致性胜过提高精度。

@drewnoakes

我理解,一致性很重要。 我认为这也回答了为什么ISet<T>不应该扩展IReadOnlySet<T> ,不过。

恕我直言,保持一致性胜过提高精度。

我认为这也回答了为什么ISet<T>不应该扩展IReadOnlySet<T> ,不过。

我认为你没有抓住重点。 这就是IList<T>ICollection<T>IDictionary<TKey, TValue>除了ISet<T>还应该被修复以实现只读视图接口的原因。 否则,每个人在围绕 BCL 的非直观设计工作都必须继续

@宾基

我不反对。 我不喜欢的一点是,有一个规定 read-_only_ 行为的合同被一个规定 read-_write_ 行为的合同扩展了。 命名不对,构图不对。 但我们来了。 我很想投票改变两者,但我怀疑这是在谈判桌上。

@光环四

当你把一个接口变成某物时,它是一个 _view_ 到某物。 视图本身_是_只读的。 假设您编写了类型安全的代码并且不会进行向上转换,如果您收到只读的内容,那么就所有意图和目的而言,它都是只读的。 这并不能保证数据不会改变。 这就像打开一个只读文件。 以只读方式打开的文件可以被另一个进程改变。 或者像对网站上的页面的只读访问权限,管理员可以在其中对数据进行读写查看,并可以从您的手下将其更改。

我不确定为什么只读在这里被认为是错误的术语。 只读_不_意味着不可变。 如果您需要,有一个完整的 nuget 包/不同的 API(其中添加/删除生成一个新对象,并且当前实例保证永远不会发生变异 - 因此是不可变的)。

我在想类似的事情。 .NET 中的“只读”对于字段来说也是一个非常弱的保证。 如果重新做一次,我相信所有这些都会更有意义。 就目前而言,务实是值得的。

所以一般来说,如果一个方法接受一个IReadOnlySomething<T>你可以假设它不会修改它。 不能保证接收方法不会向上转换引用,也不能保证接口的实现在访问时不会在内部修改自身。

在 C++ 中, const_cast削弱了const的保证,这是一种耻辱(尤其是现在使用mutable修饰符)但实际上它并没有减少它的有用性const是一项功能。 你只需要知道你在处理什么。

@binki做出了很好的区分。 名称中的 _Immutable_ 暗示了对所有相关人员的长期稳定性的硬保证。

有没有人知道为什么IList<T>不扩展IReadOnlyList<T>的权威来源?

@宾基

接口不是视图,而是契约。 该合约声明了实施者的能力。 如果实现者实际上没有实现这些功能,我会认为这是违反合同的。 该List<T>类声称它“是” IReadOnlyList<T> ,但事实并非如此。 它缺乏这种能力。

关于这个主题有多种思想流派。 我显然属于接口继承更严格地遵循类型之间的“is-a”关系的学校。 我当然支持更精细的接口组合方法,并认为List<T>及其亲属可能会从实现一些 3-4 个附加接口(读取、写入、追加等)中受益,但我当然认为接口的名称应该描述类型_可以_做什么,而不是_不能_做什么。 负面能力断言对合同没有多大意义。

@drewnoakes

就目前而言,务实是值得的。

我同意。 我们就在我们所在的地方。 如果将IList<T>更改为扩展IReadOnlyList<T>那么将ISet<T>更改为扩展IReadOnlySet<T>等是有意义的。

同时推动IReadableX<T>IWritableX<T>等接口与IReadOnlyX<T>并存是否过于多余?

有没有人知道为什么IList<T>不扩展IReadOnlyList<T>的权威来源?

显然,在加载针对较旧的 .net 框架编译的程序集时,这将是 ABI 破坏性更改。 因为在实现接口时,如果源代码依赖于隐式接口实现,大多数编译器会自动生成显式接口实现,如果您针对没有IList<T>的 BCL 编译实现IList<T> IList<T>实现IReadOnlyList<T> ,编译器不会自动创建显式的IReadOnlyList<T>实现。 如果我没看错: http :

@HaloFour由于List<>HashSet<>实现了ICollection<>IReadOnlyCollection<> ,我们已经接受了一条路径,其中IReadOnly指的是访问而不是能力。 基于此,让IAnything扩展IReadOnlyAnything非常有意义。 我同意IReadableIReadOnly但在这一点上,每个人都理解IReadOnly到 _mean_ IReadable并使用它。 事实上,我有意在我自己的代码库中延续这一点,因为在我看来,以两种方式思考事情比任何事情都更具认知负担。

我们坚持名称,但它背后的概念足够强大,我真的希望所有接口都可以扩展IReadOnly向前发展,就像我们对具体类所做的那样。

@ashmind我认为没有一个方法采用比较器是完美的。 在集合和字典中,比较器不是你可以轻易换掉的东西,因为它们决定了整个对象的结构。 此外,将比较器传递给CaseInsensitiveStringCollection或任何暗示某种比较的集合也是没有意义的。

(对于一个奇怪的集合,它确实比已经可用的扩展方法更有效地实现了Contains(T, IEqualityComparer<T>) ,它可能是一个一次性的类方法。很难想象Contains(T, IEqualityComparer<T>)是常见的足以在一个专门的界面中结束,但没有什么可以阻止这种情况的发生。)

@jnm2

我认为没有一种方法采用比较器是完美的。

只是为了澄清,我想说它应该公开比较器,而不是拿一个。 由于每个 Set 或 Dictionary 都必须具有某种相等算法,因此这可能已在接口上公开。 但我现在不记得我的用例了——比如使用与外部提供的相同的比较器创建一个集合。

虽然这个讨论提出了许多有趣的观点,但它似乎与开始这个线程的简单而明显的建议相去甚远。 这令人沮丧,因为我真的很希望看到这个问题得到解决。

正如 OP 所说,在没有 IReadOnlySet 的情况下添加 IReadOnlyList 时未能保持集合类型之间的奇偶性是不幸的,许多人已经实现了他们自己版本的 IReadOnlySet 接口作为变通方法(我自己的团队有类似的变通方法)。 这些解决方法接口并不理想,因为 corefx 类无法实现它们。 这是在框架中提供它的关键原因:如果我有一个 HashSet,我希望能够将它用作 IReadOnlySet,而无需复制或包装我已经拥有的对象。 至少对于性能而言,这通常是可取的。

接口的名称应该清楚地是 IReadOnlySet。 一致性胜过对 IReadOnlyXXX 名称的任何担忧。 那艘船已经开航了。

现有接口 (IReadOnlyCollection) 都不能更改。 .NET 的向后兼容要求不允许这样的更改。 不幸的是,比较器没有在现有的 IReadOnlyXXX 接口中公开(我也遇到过这个问题),但船再次航行了。

从实际的角度来看,唯一的问题似乎是在接口的这两个潜在定义之间。

之前由@ashmind提出:

public interface IReadOnlySet<T> : IReadOnlyCollection<T> {    
    bool Contains(T item);
    bool IsSubsetOf(IEnumerable<T> other);
    bool IsSupersetOf(IEnumerable<T> other);
    bool IsProperSupersetOf(IEnumerable<T> other);
    bool IsProperSubsetOf(IEnumerable<T> other);
    bool Overlaps(IEnumerable<T> other);
    bool SetEquals(IEnumerable<T> other);
}

最小建议:

public interface IReadOnlySet<T> : IReadOnlyCollection<T> {    
    bool Contains(T item);
}

我个人更喜欢这个最小的建议,因为可以推导出其他方法; 理想情况下,这些将作为扩展方法在 IReadOnlySet 接口上有一个标准实现,因此 IReadOnlySet 的实现者不需要提供它们。 我也觉得这个最小化的提议更符合其他最小化的 IReadOnlyXXX 接口。

@aaron-meyers 我唯一担心的是IsSubsetOf和朋友不能以_高效_的方式从Contains派生。 例如,当它是两个哈希表时,依赖Contains强制实现使用嵌套循环而不是哈希匹配。

也许一个新的接口, IComparableSet<T>可以包含集合操作。

我们已经在IEnumerable<T>上有一些集合操作的扩展方法。

@jnm2 HashSet 使用的这些方法

修改后的提案将是:

public interface IReadOnlySet<T> : IReadOnlyCollection<T> {    
    IEqualityComparer<T> Comparer { get; }
    bool Contains(T item);
}

或者,比较器可以位于单独的接口上,并且如果两个对象都实现了接口并具有相同的比较器,则集合操作的扩展方法实现将仅使用高效路由。 相同的方法可以应用于 IReadOnlyDictionary(实际上,也许它们只是使用相同的接口)。 类似 ISetComparable 的东西。 或者从@drewnoakes绘制可能有一个 IComparableSet但它没有定义集合运算符,而是定义了比较器:

public interface IComparableSet<T> : IReadOnlySet<T> {    
    IEqualityComparer<T> Comparer { get; }
}

在这种情况下, IReadOnlySet 回到仅仅定义包含:

public interface IReadOnlySet<T> : IReadOnlyCollection<T> {    
    bool Contains(T item);
}

public interface IReadOnlySet<T> : IReadOnlyCollection<T> {    
    bool Contains(T item);
}
public interface IReadOnlySetEx<T> : IReadOnlySet<T> {    
    bool IsSubsetOf(IEnumerable<T> other);
    bool IsSupersetOf(IEnumerable<T> other);
    bool IsProperSupersetOf(IEnumerable<T> other);
    bool IsProperSubsetOf(IEnumerable<T> other);
    bool Overlaps(IEnumerable<T> other);
    bool SetEquals(IEnumerable<T> other);
    IEqualityComparer<T> Comparer { get; }
}
public class HashSet<T>: IReadOnlySetEx<T>, ISet<T>
{
   // Improved implementation here.
}

public static class CollectionExtensiosn
{
    public static IEqualityComparer<T> GetComparer<T>(this IReadOnlySet<T> @set)
    {
           var setEx = <strong i="5">@set</strong> as IReadOnlySetEx<T>;
           if (setEx == null)
           {
                throw new ArgumentException("set should implement IReadOnlySetEx<T> for this method.")
           }
           return setEx.Comparer;
    }

    public static bool IsSubsetOf<T>(this IReadOnlySet<T> <strong i="6">@set</strong>, IEnumerable<T> other)
    {
         var setEx = <strong i="7">@set</strong> as IReadOnlySetEx<T>;
         if (setEx != null)
         {
              return setEx.IsSubsetOf(other);
         }
         // Non optimal implementation here.
    }

    // The same approach for dictionary.
    public static IEqualityComparer<T> GetKeyComparer<T>(this IReadOnlyDictionary<T> dictionary)
    {
           var dictionaryEx = set as IReadOnlyDictionaryEx<T>;
           if (dictionaryEx == null)
           {
                throw new ArgumentException("dictionary should implement IReadDictionaryEx<T> for this method.")
           }
           return dictionaryEx.KeyComparer;
    }

}

我们可以使用这种方法。
用法如下所示;

IReadOnlySet<string> mySet = new HashSet<string>();
bool test = mySet.IsSubsetOf(new []{"some", "strings", "set"}); // Extension method
var = mySet.GetComparer(); // Extension method

满足许多要求,IReadOnlySet是简约的。 但是 GetComparer 现在是方法,而不是属性。 但这是一个很好的权衡。

    /// <summary>
    /// Readable set abstracton. Allows fast contains method, also shows that collection items are unique by some criteria.
    /// </summary>
    /// <remarks>
    /// Proposal for this abstraction is discussed here https://github.com/dotnet/corefx/issues/1973.
    /// </remarks>
    /// <typeparam name="T">The type of elements in the set.</typeparam>
    public interface IReadOnlySet<out T> : IReadOnlyCollection<T>
    {
        /// <summary>
        /// Determines whether a <see cref="T:System.Collections.Generic.HashSet`1"/> object contains the specified
        /// element.
        /// </summary>
        /// <typeparam name="TItem">The type of the provided item. This trick allows to save contravariance and save from boxing.</typeparam>
        /// <returns>
        /// true if the <see cref="T:System.Collections.Generic.HashSet`1"/> object contains the specified element;
        /// otherwise, false.
        /// </returns>
        /// <param name="item">The element to locate in the <see cref="T:System.Collections.Generic.HashSet`1"/> object.</param>
        bool Contains<TItem>(TItem item);
    }

namespace System.Collections.Generic
{
    /// <summary>
    /// Provides the base interface for the abstraction of sets. <br/>
    /// This is full-featured readonly interface but without contravariance. See contravariant version
    /// <see cref="IReadOnlySet{T}"/>.
    /// </summary>
    /// <typeparam name="T">The type of elements in the set.</typeparam>
    public interface IReadableSet<T> : IReadOnlySet<T>
    {
        /// <summary>
        /// Gets the <see cref="Generic.IEqualityComparer{T}"/> object that is used to determine equality for the values
        /// in the set.
        /// </summary>
        /// <returns>
        /// The <see cref="Generic.IEqualityComparer{T}"/> object that is used to determine equality for the values in the
        /// set.
        /// </returns>
        IEqualityComparer<T> Comparer { get; }

        /// <summary>
        /// Determines whether a <see cref="T:System.Collections.Generic.HashSet`1"/> object contains the specified
        /// element.
        /// </summary>
        /// <returns>
        /// true if the <see cref="T:System.Collections.Generic.HashSet`1"/> object contains the specified element;
        /// otherwise, false.
        /// </returns>
        /// <param name="item">The element to locate in the <see cref="T:System.Collections.Generic.HashSet`1"/> object.</param>
        bool Contains(T item);

        /// <summary>
        /// Determines whether the current set is a proper (strict) subset of a specified collection.
        /// </summary>
        /// <returns><see langword="true"/> if the current set is a proper subset of <paramref name="other"/>; otherwise, false.</returns>
        /// <param name="other">The collection to compare to the current set.</param>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="other"/> is null.
        /// </exception>
        bool IsProperSubsetOf(IEnumerable<T> other);

        /// <summary>Determines whether the current set is a proper (strict) superset of a specified collection.</summary>
        /// <returns>true if the current set is a proper superset of <paramref name="other"/>; otherwise, false.</returns>
        /// <param name="other">The collection to compare to the current set. </param>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="other"/> is null.
        /// </exception>
        bool IsProperSupersetOf(IEnumerable<T> other);

        /// <summary>Determines whether a set is a subset of a specified collection.</summary>
        /// <returns>true if the current set is a subset of <paramref name="other"/>; otherwise, false.</returns>
        /// <param name="other">The collection to compare to the current set.</param>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="other"/> is null.
        /// </exception>
        bool IsSubsetOf(IEnumerable<T> other);

        /// <summary>Determines whether the current set is a superset of a specified collection.</summary>
        /// <returns>true if the current set is a superset of <paramref name="other"/>; otherwise, false.</returns>
        /// <param name="other">The collection to compare to the current set.</param>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="other"/> is null.
        /// </exception>
        bool IsSupersetOf(IEnumerable<T> other);

        /// <summary>Determines whether the current set overlaps with the specified collection.</summary>
        /// <returns>true if the current set and <paramref name="other"/> share at least one common element; otherwise, false.</returns>
        /// <param name="other">The collection to compare to the current set.</param>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="other"/> is null.
        /// </exception>
        bool Overlaps(IEnumerable<T> other);

        /// <summary>Determines whether the current set and the specified collection contain the same elements.</summary>
        /// <returns>true if the current set is equal to <paramref name="other"/>; otherwise, false.</returns>
        /// <param name="other">The collection to compare to the current set.</param>
        /// <exception cref="ArgumentNullException">
        /// <paramref name="other"/> is null.
        /// </exception>
        bool SetEquals(IEnumerable<T> other);
    }
}

刚刚将这个带有注入助手的合约发布到了 nuget (https://www.nuget.org/packages/ClrCoder.Collections.ReadOnlySet)。
随意使用它并在此处提交问题: https :
如果它变得有点流行(可能在经过几轮改进后),我们可以向 CoreFX 团队建议此改进。

@terrajobst可以兼容现有类来实现新接口吗?

@safernList<T>IReadOnly是有先例的。

那么是否计划在下一个 .NET 框架版本中添加?

这项工作什么时候落地? 有时间表吗?

https://www.nuget.org/packages/System.Collections.Immutable/
全套不可变集合)

好的。 这已经在这里太久了。 我非常需要它,并想提出一种方法来解决这个问题。

而不是暴露所有这些:

IEqualityComparer<T> Comparer { get; }
bool IsProperSubsetOf(IEnumerable<T> other);
bool IsProperSupersetOf(IEnumerable<T> other);
bool IsSubsetOf(IEnumerable<T> other);
bool IsSupersetOf(IEnumerable<T> other);
bool Overlaps(IEnumerable<T> other);
bool SetEquals(IEnumerable<T> other);

并强迫客户实施这些成员,让我们添加最重要的内容:

public interface IReadOnlySet<out T> : IReadOnlyCollection<T>
{
    bool Contains<T>(T item);
}

仅此而已。 如果有这样的需要,将来总是可以添加更多 API。 但它不能被删除,因此这个提议。

然后我们将此接口添加到由ISet<T>扩展的接口列表中。

从文档

ISet<T> :该接口提供了实现集合的方法,集合是具有唯一元素和特定操作的集合。 哈希集和排序集集合实现了这个接口。

从代码

ISet<T>接口已经通过ICollection<T>定义了我们的bool Contains<T>(T item);方法。 它也有int Count { get; }通过ICollection<T>

那么将是:

public interface ISet<T> : ICollection<T>, IEnumerable<T>, IEnumerable, IReadOnlySet<T>

微不足道的变化,很少讨论,巨大的好处。

请让我们实现它。 让我知道这样的拉取请求是否会被接受和合并。 那我就可以创建了。

@karelz @terrajobst @safern @ianhays

我在处理一个现实世界的问题时发现了这个讨论,我想使用字典的键集合进行只读集合操作。 为了支持这种情况,这里是我建议的 API。

基本原理

提议的API

 namespace System.Collections.Generic {
+    public interface IReadOnlySet<out T> : IReadOnlyCollection<T>, IEnumerable, IEnumerable<T> {
+        bool Contains(T value);
+        bool IsProperSubsetOf(IEnumerable<T> other);
+        bool IsProperSupersetOf(IEnumerable<T> other);
+        bool IsSubsetOf(IEnumerable<T> other);
+        bool IsSupersetOf(IEnumerable<T> other);
+        bool Overlaps(IEnumerable<T> other);
+        bool SetEquals(IEnumerable<T> other);
+    }
-    public class HashSet<T> : ICollection<T>, IDeserializationCallback, IEnumerable, IEnumerable<T>, IReadOnlyCollection<T>, ISerializable, ISet<T> {
+    public class HashSet<T> : ICollection<T>, IDeserializationCallback, IEnumerable, IEnumerable<T>, IReadOnlyCollection<T>, ISerializable, ISet<T>, IReadOnlySet<T> {
     }
-    public class SortedSet<T> : ICollection, ICollection<T>, IDeserializationCallback, IEnumerable, IEnumerable<T>, IReadOnlyCollection<T>, ISerializable, ISet<T> {
+    public class SortedSet<T> : ICollection, ICollection<T>, IDeserializationCallback, IEnumerable, IEnumerable<T>, IReadOnlyCollection<T>, ISerializable, ISet<T>, IReadOnlySet<T> {
     }
+    public class ReadOnlySet<T> : ICollection<T>, IEnumerable, IEnumerable<T>, IReadOnlyCollection<T>, IReadOnlySet<T>, ISet<T> {
+        public int Count { get; }
+        public ReadOnlySet(ISet<T> set);
+        public bool Contains(T value);
+        public bool IsProperSubsetOf(IEnumerable<T> other);
+        public bool IsProperSupersetOf(IEnumerable<T> other);
+        public bool IsSubsetOf(IEnumerable<T> other);
+        public bool IsSupersetOf(IEnumerable<T> other);
+        public bool Overlaps(IEnumerable<T> other);
+        public bool SetEquals(IEnumerable<T> other);
+    }
     public class Dictionary<TKey, TValue> {
-        public sealed class KeyCollection : ICollection, ICollection<TKey>, IEnumerable, IEnumerable<TKey>, IReadOnlyCollection<TKey> {
+        public sealed class KeyCollection : ICollection, ICollection<TKey>, IEnumerable, IEnumerable<TKey>, IReadOnlyCollection<TKey>, IReadOnlySet<TKey> {
+            public bool IsProperSubsetOf(IEnumerable<TKey> other);
+            public bool IsProperSupersetOf(IEnumerable<TKey> other);
+            public bool IsSubsetOf(IEnumerable<TKey> other);
+            public bool IsSupersetOf(IEnumerable<TKey> other);
+            public bool Overlaps(IEnumerable<TKey> other);
+            public bool SetEquals(IEnumerable<TKey> other);
         }
     }
 }

开放问题

  • 考虑到通常实例化的泛型类型的代码大小成本,将这些方法添加到Dictionary<TKey, TValue>.KeyCollection可以接受? 见这里
  • IReadOnlySet<T>应该在其他Dictionary KeyCollection例如SortedDictionaryImmutableDictionary

更新

  • 删除了TryGetValue因为它不在ISet<T> ,因此可能会阻止ISet<T>实现IReadOnlySet<T>
  • 添加ReadOnlySet<T>类似于ReadOnlyCollection<T> ReadOnlySet<T>类。

@TylerBrinkley感谢您在线程中添加 API 提案。 您介意添加基本原理和用例吗? 以便我可以将其标记为准备审查并让 api 专家决定?

@TylerBrinkley不要忘记在 IReadOnlySet 中包含 EqualityComparer 属性界面。 它们目前在 CoreFX 的 Dictionaries ans Sets 中缺失,但这是一个问题。

@dmitriyse getter only IEqualityComparer<T>属性有什么用? 你会用它做什么?

字典和集合应该报告它们的 EqualityComparers 以允许正确的集合克隆。
不幸的是我忘记了在哪里讨论这个问题。

如果你在做克隆,你不会使用具体类型吗? 为什么接口需要支持IEqualityComparer<T>

例如,如果您使用字符串和不区分大小写的相等比较器进行设置,您将在创建新 HashSet 时收到异常,而未指定正确的 EqualityComparer。 在某些情况下,您无法知道指定集合中使用了什么 EqualityComparer。

这不仅仅是克隆。 我认为更常见的场景是比较两个集合——我需要知道它们都使用相同的比较器,以便使用 Contains 实现最佳比较。 我认为这个线程中有一个例子。

也就是说,我宁愿让 IReadOnlySet 只包含 contains 方法,而不是根本没有。 能够通用地实现 Set 比较会很好,但不像只需要对 Set 的只读引用那么常见。

获取 iOS 版 Outlook https://aka.ms/o0ukef


来自:泰勒布林克利通知@ github.com
发送时间:2018 年 5 月 10 日,星期四 6:21:52
至:dotnet/corefx
抄送:亚伦迈耶斯; 提到
主题: Re: [dotnet/corefx] 请添加接口 IReadOnlySet 并使 HashSet、SortedSet 实现它 (#1973)

如果你在做克隆,你不会使用具体类型吗? 为什么接口需要支持 IEqualityComparer.


你收到这个是因为你被提到了。
直接回复本邮件,在GitHub上查看https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fdotnet%2Fcorefx%2Fissues%2F1973%23issuecomment-388051258&data=02 %7C01%7C%7Cc45ea16cd3034ddd69d808d5b678ff33%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C636615553141417289&SDATA = xRI27JtyaAwnZ2anY05oTlxmPY5AaGVl%2BRdXK2uR0%2F8%3D&保留= 0 ,或静音螺纹https://eur01.safelinks.protection.outlook.com/?url=https%3A% 2F%2Fgithub.com%2Fnotifications%2Funsubscribe-AUTH%2FAMuQLmqboBWyHweWHSUoE1YM2OrfHZZxks5txD7wgaJpZM4E9KK-&数据= 02%7C01%7C%7Cc45ea16cd3034ddd69d808d5b678ff33%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C636615553141417289&SDATA = hLtAXEyFNVEgWike6tMwAfUVC%2BucyjXUDwoLOLDV5gk%3D&保留= 0

我同意——你可以通过暴露比较器来判断你可能在集合中找到哪些类型的重复项(区分大小写、不区分大小写等)的唯一方法。

我开始认为我的提议不会被接受,因为将所有这些方法添加到Dictionary<TKey, TValue>.KeyCollection会产生很大的代码大小成本。 请参阅有关向常用实例化泛型类型添加新 API 的讨论

我认为您无法在IReadOnlySet上放置比较器。

SortedSet需要一个IComparer ,而HashSet需要一个IEqualityComparer

好点,比较器可以被认为是一个不属于通用接口的实现细节。

获取 iOS 版 Outlook https://aka.ms/o0ukef


来自:Cory Nelson [email protected]
发送时间:2018 年 5 月 10 日星期四下午 5:04:06
至:dotnet/corefx
抄送:亚伦迈耶斯; 提到
主题: Re: [dotnet/corefx] 请添加接口 IReadOnlySet 并使 HashSet、SortedSet 实现它 (#1973)

我认为您无法在 IReadOnlySet 上放置比较器。

SortedSet 采用 IComparer,而 HashSet 采用 IEqualityComparer。


你收到这个是因为你被提到了。
直接回复本邮件,在GitHub上查看https://eur02.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fdotnet%2Fcorefx%2Fissues%2F1973%23issuecomment-388221165&data=02 %7C01%7C%7C0ef6d84125be4c450fdc08d5b6d2b70a%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C636615938478979295&SDATA = PHkDQPiJBEIks8yNyIA7vKODM%2BkMFI4PRX4lUUBu%2Bi0%3D&保留= 0 ,或静音螺纹https://eur02.safelinks.protection.outlook.com/?url=https%3A% 2F%2Fgithub.com%2Fnotifications%2Funsubscribe-AUTH%2FAMuQLu5JGLcqrpMyGWLygbCsaSQSXFgNks5txNV2gaJpZM4E9KK-&数据= 02%7C01%7C%7C0ef6d84125be4c450fdc08d5b6d2b70a%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C636615938478979295&SDATA = 9pnuMULuDu9HWb7un%2FWYq6iYdjTKFsjN7nKiToaeHkk%3D&保留= 0

添加IUnorderedSetIOrderedSet接口可能会有一些价值,但我不希望这会破坏推动IReadOnlySet通过。

我喜欢@pgolebiowski的建议,但会使该界面更加基本。

c# public interface ISetCharacteristic<in T> { bool Contains(T item); }

这也适用于不可数集,例如区间(实数)。 在它和IReadOnlySet您可能会适合其他一些接口,例如ICountableSet (又名IEnumerableSet )、 IUnorderedSetIOrderedSet

但是同意仅IReadOnlySet将比当前可用的有很大的改进。

+1 @NickRedwood

它已经开放3年多了。 请通过改变方法来实现这一点。 引入@NickRedwood提到的

@TylerBrinkley @safern @karelz @terrajobst

我真的没有看到只有Contains方法的IReadOnlySet<T>接口有多大好处。 虽然该方法很有用,但它已经包含在ICollection<T>接口中,该接口还有一个IsReadOnly属性,用于指示是否支持ICollection<T>的修改方法。 只需实现ICollection<T>并使IsReadOnly返回true 。 它预计支持的唯一其他功能是Count属性(可枚举)和CopyTo方法,该方法似乎没有太大限制。

我很高兴基于IReadOnlyCollection<T>实施提议的IReadOnlySet<T> IReadOnlyCollection<T> - 这将是对当前可用内容的重大改进。 ( @TylerBrinkley - 假设你的意思是IReadOnlyCollection<T>而不是ICollection<T>

我想我在更基本的接口方面犯了错误,如果 Set 有一个接口,那么它将是一个带有Contains方法的单方法接口。 它具有良好的数学基础并且非常干净。 不过改装现有的类时,我接受改造越少越好,如果有是那么只有一个接口加装IReadOnlySet<T>基于IReadOnlyCollection<T>应该是它。

IReadOnlyCollection<>没有.Contains因为这会阻止它协变。

好点,我已将我之前的帖子更正为逆变。 IReadOnlySet<T>需要保持不变,除非使用线程中早期发布的方法,我不确定那个方法。

@TylerBrinkley我个人不是IsReadOnly属性的粉丝,我更愿意在编译时而不是运行时知道这些信息。 如果您指的是IReadOnlyCollection<T>接口,那么我仍然认为调用者或被调用者知道查找将很快而不是通过集合进行潜在迭代会很有用,尽管我不确定是否“集合”暗示了这一点。

只有一个Contains方法并没有定义Set应该做什么,只是Collection应该做什么。 我的意思是Contains甚至不是ISet的成员,而是ICollectionISet继承自。 应该要求ISet的其他成员定义Set应该做什么。 我知道大多数人可能专门使用集合来使用它的Contains方法,但是集合远不止这些。

@TylerBrinkley但是此时甚至可以定义IReadOnlyCollection<T>.Contains(T)吗? 我以为没有。 这就是为什么唯一的选择是引入IReadOnlySet<T>并且在引入时确保在其上声明IReadOnlySet<T>.Contains(T)

@jnm2说:

IReadOnlyCollection<>没有.Contains因为这会阻止它协变。

这对我来说似乎是目前最大的问题。 当IReadOnlyCollection<T>是协变的时, IReadOnlySet<T>是不变的会很奇怪。 似乎许多现有的IReadOnly*接口都被精心设计为out T ,可写接口必然是不变的。 我们大多数人都希望IReadOnlySet<T>至少声明一个Contains(T)方法,但这会阻止它协变。

如果ICollection确实是定义Contains(T)的正确位置,那可能吗? 也许IReadOnlyProbableCollection<T>.Contains(T)是不变的并由Collection<T>HashSet<T>

我认为@NickRedwood 的ISetCharacteristic<T>似乎更清晰。 这甚至具有允许您不实现可能有用的Count的好处。

我个人不是 IsReadOnly 属性的粉丝,我更希望在编译时而不是运行时知道这些信息。

那人说得好,再给他倒酒。

@binki我同意IReadOnlySet<T>上需要有一个Contains方法,因为IReadOnlyCollection<T>不包括一个,但是我也认为所有其他非变异的ISet<T>方法应该包括在内。

除了我上面提到的Dictionary.KeyCollection用例之外,您还能想出哪些其他用例来添加此接口?

好的,看起来 API 设计是:

public interface IReadOnlySet<T> : IReadOnlyCollection<T> {    
    bool Contains(T item);
}

这是每个人似乎都能同意的设计中唯一的共同部分。

我说现在我们在这里结束设计。 如果您想在将来扩展它,请在不同的问题中进行。 这是应该在产品中的最重要的功能。

谁支持谁反对?

我喜欢@ashmind建议。 如果 Dictionary.Keys 可以实现这个接口,那就太棒了,因为它在技术上是IReadOnlySet<TKey>

你能把它标记为api-ready-for-review吗? 我刚刚发现自己再次需要这个界面,但它仍然不存在。

为什么这还没有实施?

[编辑] 抱歉 - 我的原始回复与另一个 API 混淆了。 我对这个没有强烈的意见,文本编辑。 抱歉造成混乱!

为什么这还没有实施?

API 尚未引起区域所有者的注意 - @safern。 我不确定它在收藏优先级列表中有多高。 投票数相当高。
事实是,我们现在正在锁定 .NET Core 3.0,因此它必须至少等待下一个版本,因为它对 3.0 并不重要。

我也很惊讶这不是开箱即用的。

不可变数据结构可以极大地帮助提高代码的可维护性,但是如果没有标准库中指定语义并允许不同实现协同工作的接口,它们就很难使用。

如果没有这个,每个库意味着使用不可变集作为参数/返回值需要求助于使用效率较低且语义不正确的 IEnumerable 或在其签名中使用自己的接口/类,这与其他人的不兼容。

我很好奇是否有任何解决方法可以在Contains查找方面有效并避免指定参数/返回值的具体类型。 我能想到的最好的办法是在签名中使用 IEnumerable 并传递 ReadOnlyDictionary.Keys,但这似乎有点讨厌,尤其是在库中。 由于 Linq 中的Enumerable.Contains将使用Contains的集合实现,这在兼容的情况下应该是有效的,但不会传达可能导致使用性能较低的实现的意图。

@adamt06您正在寻找ISet<T>

@scalablecory你是对的,有一个不可变的实现,有一个: ImmutableHashSet<T>

有谁知道/理解为什么 ICollection不扩展 IReadOnlyCollection??
我认为这与这个线程有点相关。 而不是我打开一个新线程。 也许我只是误解了一些东西。

另一个想法,但完全偏离主题,为什么 ReaOnlyCollection 没有:

c# bool Contains(T item); void CopyTo(T[] array, int arrayIndex);

哦,我明白你的意思是 IReadOnlyCollection 没有它们。 这是因为否则接口不能是协变的

我不确定,但这可能与显式接口实现有关,导致向后兼容性问题。 我可以理解为什么更新现有接口以从其他接口继承是一个问题,但我不明白为什么创建一个新接口IReadOnlySet<T>并让HashSet实现它会是一个问题。

好的。 但是还是看不到ICollection不应该是:
c# ICollection<T> : IReadOnlyCollection<out T>
为什么读/写集合不应该也是只读集合的​​扩展?

@generik0

好的。 但是还是看不出ICollection不应该是:

ICollection<out T> : IReadOnlyCollection<out T>

为什么读/写集合不应该也是只读集合的​​扩展?

首先,请注意不能声明ICollection<out T>因为ICollection<T>有一个成员.Add(T item)

其次,请注意ICollection<T>出现在 .net-2.0 中,IReadOnlyCollection<out T>出现在 .net-4.5 中。 如果您将代码编译为实现ICollection<T> ,然后将ICollection<T>更改为实现新接口,则任何现有编译的二进制文件都将在运行时中断,因为仅实现ICollection<T>任何东西都不会IReadOnlyCollection<T>槽由编译器填充(可能自动)。 这是阻止ICollection<T>实现IReadOnlyCollection<T>的兼容性问题。

我不认为这个 SO answer 清楚地解决了这个问题,但有一个 SO : https://stackoverflow.com/a/14944400

@binki "ICollection" 固定到 ICollection, 谢谢你指出我的错字..
DotNetStandard i net461。 这就是应该改变的地方。 网络标准 2+

我会重复...
为什么读/写集合不应该也是只读集合的​​扩展?

为什么需要将一个集合转换为例如“ToArray()”只是为了减少暴露?

因为您可以在更高版本中添加新接口而不会破坏事物。 ICollection 已经实现了 IReadOnlyCollection 方法。 注意应该中断,...:-/

@generik0看起来它不会破坏源兼容性,这正是您所想的[没想到; 它会],但它会破坏适用于 IL 表而不是 C# 的二进制兼容性。

好的@jnm2谢谢。
我现在停止我的题外话,只是认为它是糟糕的架构。 感谢大家的聆听/解释:-)

@jnm2

@generik0看起来它不会破坏您正在考虑的源代码兼容性,但它会破坏适用于 IL 表而不是 C# 的二进制兼容性。

吹毛求疵(抱歉),如果您的源代码在 .net-4.5 之前明确实现了ICollection<T> ,它也会破坏源代码兼容性。 由于未能显式实现IReadOnlyCollection<T>.Count ,该类将开始无法编译。 但是二进制兼容性是一个更大的问题,因为它会阻止您针对范围广泛的 .net 版本(无论如何,您必须拥有不同的二进制文件才能在 ≥.net-4.5 上运行而不是 <.net-2 并且您会必须同时针对两者,而不仅仅是针对较旧的框架)。

我想知道在 C#8 中添加默认接口实现支持是否ICollection<T>可以为 .NET Core 3.0+ 实现IReadOnlyCollection<T>

也许需要一个扩展,那么它至少是同一个集合。 即,如果您需要将 ienumerable 或 icollection 转换为 reaadonlycollection ... 有什么想法吗?

[由@jnm2评论编辑]
c# public static class CollectionExtensions { public static IReadOnlyCollection<T> CastAsReadOnlyCollection<T>(this IEnumerable<T> collection) { if((collection is IReadOnlyCollection<T> readOnlyCollection )) { return readOnlyCollection ; } throw new ArgumentException($"{collection.GetType()} not supported as readonly collection"); } }

@generik0为什么不使用enumerable as IReadOnlyCollection<T> ?? throw ...(IReadOnlyCollection<T>)enumerable而不是调用该方法?

@jnm2 天啊。 你是对的。 有时你看不到清晰的画面,把事情复杂化!!!

我仍然会调用扩展程序,只是为了简单;-)
谢了哥们....

这里是什么状态? 我真的很喜欢标准库中的这个接口,并让 HashSet<> 实现它。

似乎我们最好的选择可能是等待更长时间,以便(希望)实施 Shapes 提案。 然后,您将能够构建任何形状组来表示您想要的 Set 类型,并提供实现以便像HashSet<T>这样的现有集合符合它们。

然后可能会出现一个社区库来做到这一点,涵盖所有各种类型的集合(内涵(谓词)和外延(列出)、有序、偏序、无序、可数、可数无限、不可数无限、可能的数学领域也像 Rational ,自然数等)作为不同的形状,以及为这些集合定义的所有并集、交集、基数方法。

对我来说,这听起来像是 5 年后的道路。 为什么可以在一天内实现的简单更改要等待一些甚至可能不会发生的 1000 倍大的尚未指定的功能?

对我来说,这听起来像是 5 年后的道路。 为什么可以在一天内实现的简单更改要等待一些甚至可能不会发生的 1000 倍大的尚未指定的功能?

我只是对IReadOnlySet<T>缺乏进展做出回应——毕竟这个问题已经存在 4 年了。

微软的方式:最简单有用的事情需要几十年的时间。 真是令人兴奋。 5 年和计数。

更有趣的是他们在这里
https://docs.microsoft.com/en-us/dotnet/api/microsoft.sqlserver.management.sdk.sfc.ireadonlyset-1

@terrajobst想法?

  • 我们普遍认为这确实是我们界面层次结构中的一个漏洞。 我们建议只关注添加接口并在现有集合实现上实现它。 我们不能让ISet<T>扩展IReadOnlySet<T> (出于同样的原因,我们不能为其他可变接口做)。 我们可以在稍后阶段添加ReadOnlySet<T> 。 我们应该仔细检查IReadOnlySet<T>是否只是ISet<T>减去可变 API。
  • 我们还应该在ImmutableSortedSet<T>ImmutableHashSet<T> (以及它们的构建器)上实现IReadOnlySet<T>
  • 我们应该扫描ISet<T>其他实现。
 namespace System.Collections.Generic {
+    public interface IReadOnlySet<out T> : IReadOnlyCollection<T>, IEnumerable, IEnumerable<T> {
+        bool Contains(T value);
+        bool IsProperSubsetOf(IEnumerable<T> other);
+        bool IsProperSupersetOf(IEnumerable<T> other);
+        bool IsSubsetOf(IEnumerable<T> other);
+        bool IsSupersetOf(IEnumerable<T> other);
+        bool Overlaps(IEnumerable<T> other);
+        bool SetEquals(IEnumerable<T> other);
+    }
-    public class HashSet<T> : ICollection<T>, IDeserializationCallback, IEnumerable, IEnumerable<T>, IReadOnlyCollection<T>, ISerializable, ISet<T> {
+    public class HashSet<T> : ICollection<T>, IDeserializationCallback, IEnumerable, IEnumerable<T>, IReadOnlyCollection<T>, ISerializable, ISet<T>, IReadOnlySet<T> {
     }
-    public class SortedSet<T> : ICollection, ICollection<T>, IDeserializationCallback, IEnumerable, IEnumerable<T>, IReadOnlyCollection<T>, ISerializable, ISet<T> {
+    public class SortedSet<T> : ICollection, ICollection<T>, IDeserializationCallback, IEnumerable, IEnumerable<T>, IReadOnlyCollection<T>, ISerializable, ISet<T>, IReadOnlySet<T> {
     }
 }

做吧,我敢!

@terrajobst

我们不能让ISet<T>扩展IReadOnlySet<T> (出于同样的原因,我们不能为其他可变接口做)。

即使使用默认接口方法,这仍然是真的吗? 这是否意味着应该关闭https://github.com/dotnet/corefx/issues/41409

@terrajobst

我们不能让ISet<T>扩展IReadOnlySet<T> (出于同样的原因,我们不能为其他可变接口做)。

即使使用默认接口方法,这仍然是真的吗? 这是否意味着dotnet/corefx#41409应该关闭?

我们讨论了这个。 我们曾经认为 DIM起作用,但是当我们执行解决方案时,我们得出结论,它通常会导致碎片菱形,从而导致模糊匹配。 然而,这最近受到了挑战,所以我想我必须把它写下来并确保它确实有效或无效。

@terrajobst / @danmosemsft有没有人被分配到这个?

而且, @terrajobst澄清我们想要实现的工作是:
``
我们还应该实现 IReadOnlySet在 ImmutableSortedSet 上和 ImmutableHashSet(和他们的建设者)
我们应该扫描 ISet 的其他实现.
````
以及在HashSet、SortedSet上实现上述接口。

扫描只是寻找任何东西,如果它看起来有问题就提出来。

如果这仍然可以抢夺我会感兴趣

@Jlalond不,分配给您。 谢谢你的报价。

@danmosemsft @terrajobst
只是一个更新。 我正在研究这个,将接口添加到私有核心 Lib,只是通过 collections.generic 和 immutable 来解决这个问题。

最后一个问题,如果您知道 Dan​​,我是否需要为此对 Mono 进行任何更改? 我对 corefx 在哪里结束和单声道开始没有洞察力。 所以如果你知道它可以让我免于一些独立的研究

@Jlalond您不需要对 Mono 进行更改。 将 Mono 运行时移入此存储库的部分原因是,可以无缝地将相同的库与 CoreCLR 或 Mono 运行时一起使用。 核心库中只有一小部分存在分歧:
coreclrsrcSystem.Private.CoreLib 与 mononetcoreSystem.Private.CoreLib。 (大部分核心库是在librariesSystem.Private.CoreLib 之外共享的)。 所以除非你碰它——你不会受到影响。

@danmosemsft感谢您的澄清,我希望尽快完成。

@danmosemsft只是跟进这个。 CoreLib 正在 src 程序集中构建,我可以看到引用的更改。 然而,ref 程序集似乎没有检测到任何变化。 这就是阻碍我的全部内容,但我在文档中找不到任何信息。 您可以给我任何人或指示,以便我完成这项工作(我的意思是,5 年后)

由 #32488 寻址

此页面是否有帮助?
0 / 5 - 0 等级