在一个属性中使用代码契约来提供关于另一个属性的提示

本文关键字:属性 提示 另一个 契约 一个 代码 | 更新日期: 2023-09-27 18:10:29

我有一个这样的struct(简化为简洁):

public struct Period
{
    public DateTime? Start { get; private set; }
    public DateTime? End { get; private set; }
    public bool IsMoment
    {
        get { return this.Start.HasValue && this.Start == this.End; }
    }
    public Period(DateTime? start, DateTime? end) : this()
    {
        this.Start = start;
        this.End = end;
    }
    public override string ToString()
    {
        return this.IsMoment 
            ? this.Start.Value.ToString("g") 
            : string.Format("{0:g} – {1:g}", this.Start, this.End);
    }
}

一切正常,但ReSharper在this.Start.Value.ToString上显示警告:

可能的' System.InvalidOperationException '

如果我将IsMoment属性的主体复制到条件中,则警告将消失,但我希望能够重用该属性。我可以用注释禁用ReSharper警告(这就是我目前所做的),或者通过将ToString更改为string.Format,但是我的代码中有一些其他类似的地方,它让我思考。我试着用代码契约来解决这个问题,但不幸的是,我没有很多代码契约的经验,我不确定它会是什么样子。

是否有我使用代码合同来指示ReSharper,如果IsMomenttrue,那么Start不是null ?

在一个属性中使用代码契约来提供关于另一个属性的提示

在IsMoment:

合同。确保(result == false || start <> null);

)这并不完全正确。我正在用手机打这个

更新:

这个问题可能是由于多线程代码在IsMoment测试和Start测试之间改变Start值的可能性。价值评估。

将值复制到其他线程不能修改的局部变量中可能更正确。

public override string ToString()
{
    Period local = this;
    return local.IsMoment 
        ? local.Start.Value.ToString("g") 
        : string.Format("{0:g} – {1:g}", local.Start, local.End);
}

这看起来像是一些不必要的工作,它可能看起来效率低下,但它更"正确"。但是,如果您的结构很小,那么在许多情况下,这实际上可能更有效。

是否尝试过在它周围包装父母?

public override string ToString()
{
    return (this.IsMoment 
        ? this.Start.Value.ToString("g") 
        : string.Format("{0:g} – {1:g}", this.Start, this.End));
}

这可能是使用Contract.Assume的情况。

public override string ToString()
{
   if (this.IsMoment) {
      Contract.Assume(this.Start.HasValue);
      return this.Start.Value.ToString("g");
   }
   else
      return string.Format("{0:g} – {1:g}", this.Start, this.End));
}