ReSharper好奇心:"参数仅用于前置条件检查."

Cor*_*ker 92 c# resharper preconditions

为什么ReSharper会判断我这个代码?

    private Control GetCorrespondingInputControl(SupportedType supportedType, object settingValue)
    {
        this.ValidateCorrespondingValueType(supportedType, settingValue);

        switch(supportedType)
        {
            case SupportedType.String:
                return new TextBox { Text = (string)settingValue };
            case SupportedType.DateTime:
                return new MonthPicker { Value = (DateTime)settingValue, ShowUpDown = true };
            default:
                throw new ArgumentOutOfRangeException(string.Format("The supported type value, {0} has no corresponding user control defined.", supportedType));
        }
    }

    private void ValidateCorrespondingValueType(SupportedType supportedType, object settingValue)
    {
        Type type;

        switch(supportedType)
        {
            case SupportedType.String:
                type = typeof(string);
                break;
            case SupportedType.DateTime:
                type = typeof(DateTime);
                break;
            default:
                throw new ArgumentOutOfRangeException(string.Format("The supported type value, {0} has no corresponding Type defined.", supportedType));
        }
        string exceptionMessage = string.Format("The specified setting value is not assignable to the supported type, [{0}].", supportedType);
        if(settingValue.GetType() != type)
        {
            throw new InvalidOperationException(exceptionMessage);
        }
    }
Run Code Online (Sandbox Code Playgroud)

第二种方法ValidateCorrespondingValueType的"settingValue"参数显示为灰色,ReSharper使用以下消息:"参数'settingValue'仅用于前置条件检查."

cit*_*att 96

这不是判断,它试图帮助:)

如果ReSharper看到一个参数仅用作检查以抛出异常,它会将其变灰,表明您实际上并未将其用于"真实"工作.这很可能是一个错误 - 为什么要传递一个你不会使用的参数?它通常表示您已在先决条件中使用它,但后来忘记(或不再需要)在代码中的其他位置使用它.

由于该方法是一个断言方法(也就是说,它所做的只是断言它是有效的),你可以通过ValidateCorrespondingValueType使用ReSharper的注释属性,特别是[AssertionMethod]属性标记为断言方法来抑制消息:

[AssertionMethod]
private void ValidateCorrespondingValueType(SupportedType supportedType, object settingValue)
{
  // …
}
Run Code Online (Sandbox Code Playgroud)

  • 它可能是一个有用的功能,如果可以独立于常规未使用的参数检查禁用"仅预先条件"检查; 因此,检查混合了两个不同严重程度的问题,并且通常使得该功能在某些情况下无用.我也非常怀疑为了保持源代码分析工具满意而在代码中添加注释或属性的想法,所以目前我认为这个问题没有令人满意的解决方案. (60认同)
  • 我最后只是将检查严重性更改为"不显示",这是另一种选择. (9认同)
  • 它可能试图帮助,但它过于激进.现在,如果您验证该值然后从不使用它,那很好,这可能是一个错误.然而,它只是在一个我只使用错误值的地方.除了故意之外,还有什么可以做的呢? (7认同)
  • 这就是为什么你需要告诉ReSharper它是一个断言方法.该方法的唯一要点是对另一种方法执行前置条件检查.这是一个断言,但ReSharper无法知道,除非你用`[AssertionMethod]`告诉它. (6认同)
  • 这是一个很好的检查,但在*这个案例中R#已经过了一点,你不是吗?检查`settingValue`的类型不可能是**pre** - 条件,因为在方法体内完成某些工作后才能知道它被检查的东西! (3认同)
  • 我不喜欢仅仅为了消息而在我的解决方案中添加另一个组件 (2认同)

Hol*_*olf 17

有趣的是,如果你使用nameofC#6中的新功能,ReSharper会退缩:

static void CheckForNullParameters(IExecutor executor, ILogger logger)
{
    if (executor == null)
    {
        throw new ArgumentNullException(nameof(executor));
    }

    if (logger == null)
    {
        throw new ArgumentNullException(nameof(logger));
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这个答案适合我,它比添加nuget包更少侵入 (3认同)

Eam*_*nne 5

我首选的解决这个问题是让ReSharper的认为参数使用.这比使用属性的优势,比如UsedImplicitly,因为如果你永远 停止使用该参数,ReSharper的将开始再次警告你.如果使用属性,resharper也不会捕获未来的真实警告.

使resharper认为使用参数的一种简单方法是用throw方法替换.而不是......

if(myPreconditionParam == wrong)
    throw new Exception(...);
Run Code Online (Sandbox Code Playgroud)

...你写:

if(myPreconditionParam == wrong)
    new Exception(...).ThrowPreconditionViolation();
Run Code Online (Sandbox Code Playgroud)

对于未来的程序员来说,这很好地自我记录,并且resharper退出了抱怨.

ThrowPreconditionViolation的实现是微不足道的:

public static class WorkAroundResharperBugs 
{
    //NOT [Pure] so resharper shuts up; the aim of this method is to make resharper 
    //shut up about "Parameter 'Foobaar' is used only for precondition checks" 
    //optionally: [DebuggerHidden]
    public static void ThrowPreconditionViolation(this Exception e)
    {
        throw e;
    }
}
Run Code Online (Sandbox Code Playgroud)

Exception的一个扩展方法命名空间污染,但是它被公平地包含了.


小智 5

以下修复了该问题(在ReSharper 2016.1.1,VS2015中),但我不确定它是否解决了"正确"的问题.无论如何,它显示了ReSharper关于这个主题的机制的模糊性:

这会产生警告:

    private void CheckForNull(object obj)
    {
        if (ReferenceEquals(obj, null))
        {
            throw new Exception();
        }
    }
Run Code Online (Sandbox Code Playgroud)

但这不是:

    private void CheckForNull(object obj)
    {
        if (!ReferenceEquals(obj, null))
        {
            return;
        }
        throw new Exception();
    }
Run Code Online (Sandbox Code Playgroud)

有趣的是,等效代码(由ReSharper:D完成的反演)给出了不同的结果.似乎模式匹配根本没有拿起第二个版本.