【发布时间】:2021-08-20 08:54:46
【问题描述】:
我有一个相对简单的扩展方法,叫做 TryGetFirst
public static bool TryGetFirst<T>(this IList<T> list, out T value)
{
if (list == null || list.Count == 0)
{
value = default;
return false;
}
value = list[0];
return true;
}
它同时做几件事情。它 null 检查列表,检查列表是否为空,如果不是,则返回第一个元素。有点像 Linq 的 FirstOrDefault 但有一个内置的空检查。没什么太花哨的。
我正在寻找正确的 ContractAnnotation 语法来将以下事实传达给 ReSharper,但我似乎无法将它们全部确定下来。
- 如果列表为 null,则始终返回 false
- 如果返回值为真,则列表不为空
- 如果返回值为false,则值为null
鉴于以下代码,我期望以下 ReSharper 提示,至少在 Rider 的悲观值分析模式下
if (StringExtensions.TryGetFirst<object>(null, out object value) { ... } // Expression is Always False
if (_possiblyNullList.TryGetFirst<object>(out object value)
{
_possiblyNullList.DoSomething(); // No Warning
value.DoSomething(); // Possible NullReferenceException
}
else
{
_possiblyNullList.DoSomething(); //Possible NullReferenceException
if (value == null) { ... } // Expression is Always True
}
起初我尝试了[ContractAnnotation("list:null => false; => false, value:null")],但由于某种原因,ReSharper 解释为所有代码路径总是返回 false,因此无法访问 if { ... } 的内容。
接下来我尝试了[ContractAnnotation("list:null => false; => false, value:null; => true")],因为我认为在最后添加真实案例会告知 ReSharper 真实结果是可能的。这稍微好一些,但是 if 块中的 _possiblyNullList.DoSomething(); 被标记为可能的 NullReference,StringExtensions.TryGetFirst<object>(null, ... 不再被标记为 Always False。
我最接近我的目标的是[ContractAnnotation("=> true, list:notnull, value:canbenull; => false, list:canbenull, value:null")],它处理除了StringExtensions.TryGetFirst<object>(null, ... 之外的所有情况,它没有被标记为Always False。我尝试添加回list:null => false 行,但没有任何区别。我也觉得这种语法比看起来需要的要冗长得多,但如果它是准确的,我愿意接受它。
我觉得我的排列组合已经用完了。这只是属性不支持的情况,还是我遗漏了一些明显的东西?
【问题讨论】:
-
看来
[ContractAnnotation("list:null => false, value:null")]可以解决问题。至少有指定的要求。 -
@GuruStron 另一个非常接近的,但至少据我所知,它不会像在 else 块中那样标记
if (value == null) { ... }。存在list不为null但返回值为false的情况,因此out值为null。
标签: c# resharper jetbrains-ide rider