我有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
,但我的代码和其他几个地方都是这样的它让我思考。我尝试使用code contracts来解决这个问题,但不幸的是我没有很多代码合同的经验,而且我不确定它的外观。
无论如何我使用代码合同向ReSharper表明如果IsMoment
是true
,那么Start
不是null
?
答案 0 :(得分:1)
在IsMoment中执行类似的操作:
contract.ensures(result == false || start<> null);
(那不完全正确。我在手机上输入此内容。)
更新:
问题可能是由于多线程代码可能会更改IsMoment测试和Start.Value评估之间的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);
}
这看起来像是一些不必要的工作,它可能看起来效率低下,但它更多"正确"。但是,如果您的结构很小,那么在许多情况下这实际上可能更有效。
答案 1 :(得分:0)
试过在它周围包裹parens?
public override string ToString()
{
return (this.IsMoment
? this.Start.Value.ToString("g")
: string.Format("{0:g} – {1:g}", this.Start, this.End));
}
答案 2 :(得分:0)
这可能是使用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));
}