c#代码契约——如何确保项目集合包含具有唯一属性的项目

本文关键字:项目 包含具 集合 唯一 属性 确保 契约 代码 何确保 | 更新日期: 2023-09-27 18:17:48

基本上,我有以下内容:

public class MyClass
{
    public MyClass(ICollection<MyObject> coll)
    {
        Contract.Requires(coll != null);
        Contract.Requires(Contract.ForAll(coll, obj => obj != null));
        Contract.Requires(Contract.ForAll(coll, obj => (????)); //What goes here?
    }
}
public class MyObject
{
    public object PropA { get; set; }
    public object PropB { get; set; }
}

要求如下:

  • 集合中的所有PropA项目都是唯一的(没有重复)
  • 集合中的所有PropB项目都是唯一的(没有重复)

我似乎不知道该怎么处理我的Contract.ForAll(...)语句。


奖励:如果我可以组合Contract.ForAll(...)语句而不破坏代码契约?

c#代码契约——如何确保项目集合包含具有唯一属性的项目

我可能在这里完全错了,从来没有使用过契约,但假设Contract.Requires可以传递任意的bool,你不能这样做:

Contract.Requires(coll.GroupBy(o => o.PropA).Count() == coll.Count);

PropB ?

我相信下面的方法可以达到这个效果:

Contract.Requires(
    Contract.ForAll(
        coll, 
        obj => (coll.Where(x=>x.PropA = obj.PropA).Count==1)
    )
);

理论是,它将coll过滤到那些PropA值与我们正在查看的对象相同的元素。应该只有其中一个(它本身)。

可以对b进行类似的重复。

它在理论上是微不足道的组合ForAll lambda表达式,但我不确定你会想要。当然,如果一个条件失败了,那么知道哪个条件失败了会更好,而不是把它们放在一起,只知道某个条件失败了,而不是真正的失败了……

如果你能在格式上给点余地,你可以试试:

Contract.Requires(
    Contract.ForAll(
        coll.GroupBy(x=>x.PropA), 
        group => group.Count==1)
    )
);

这是一个类似的原则,但我认为将做计数更有效,因为组by和计数将更有效(我认为-我没有测试过,不熟悉linq方法的内部工作)。

的另一个方法:

HashSet<object> propAValues = new HashSet<object>();
Contract.Requires(
    !coll.Any(x=>!hashset.Add(x.PropA))
);

使用哈希集,如果元素已经存在,则Add返回false。在这种情况下,Add生成一个false(因此lambda表达式为真),那么Any将返回真,因为它是否定的,因此测试将失败。

这个方法是否合理可能取决于你的对象有多大(因此倍增你的对象集的潜在内存影响)。然而,与这里的其他方法相比,它将花费最少的迭代来终止(因为其他方法需要查看集合中的每个对象,可能需要多次,而最后一个方法可能在查看两个条目后停止)。