ReSharper好奇心:“参数仅用于前提条件检查。”


102

为什么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);
        }
    }

ReSharper使用以下消息将第二种方法ValidateCorrespondingValueType的“ settingValue”参数显示为灰色:“参数'settingValue'仅用于前提条件检查”。


您可以将-的声明和赋值移动exceptionMessageif
-block

您也可以在以下方法中执行此操作:ExpectedText + =“”; 因为您在方法中使用了它,所以它不再抱怨。
PHPGuru

Answers:


104

这不是判断,而是在尝试帮助:)

如果ReSharper看到参数仅用作引发异常的检查,则会将其显示为灰色,表明您实际上并未将其用于“实际”工作。这很可能是一个错误-为什么要传递不使用的参数?它通常表明您已经在前提条件中使用了它,但是随后忘记了(或不再需要)在代码的其他地方使用它。

由于该方法是断言方法(也就是说,它所做的全部是断言它是有效的),因此可以ValidateCorrespondingValueType使用ReSharper的注释属性(特别是该[AssertionMethod]属性)将标记为断言方法来抑制消息。

[AssertionMethod]
private void ValidateCorrespondingValueType(SupportedType supportedType, object settingValue)
{
  // …
}

3
这是一个很好的检查,但是在这种情况下,R#超出了一点,您不是说吗?对settingValue类型的检查不可能是前提条件,因为要检查的对象是未知的,直到在方法体内完成某些工作为止!
AakashM 2014年

6
这就是为什么您需要告诉ReSharper这是一种断言方法的原因。该方法的唯一目的是对另一种方法执行前提条件检查。这是一个断言,但是ReSharper不能知道这一点,除非您使用来告诉它[AssertionMethod]
citizenmatt

10
我最终只是将“检查严重性”更改为“不显示”,这是另一种选择。
reggaeguitar 2014年

61
如果可以独立于常规未使用的参数检查而禁用“仅前提条件”检查,则这可能是一项有用的功能;就目前情况而言,检查会混淆两个严重性不同的问题,并且通常会使此功能在某些情况下无用。我也很怀疑仅在代码中添加注释或属性以使源代码分析工具满意的想法,因此,目前我认为还没有令人满意的解决方案。
Serge Belov

7
它可能在尝试提供帮助,但过于激进。现在,如果您验证该值,然后再不使用它,那很好,那很可能是错误。但是,它在我只使用错误中的值的情况下对我大喊大叫。除了故意,那又怎么可能呢?
罗伦·佩希特尔

20

有趣的是,如果您使用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));
    }
}

3
这个答案适合我,它是不是添加NuGet包较少侵入
DanielV

8

以下内容解决了该问题(在ReSharper 2016.1.1,VS2015中),但是我不确定它是否可以解决“正确”的问题。无论如何,它显示了ReSharper在此主题上的技巧上的歧义:

这将产生警告:

    private void CheckForNull(object obj)
    {
        if (ReferenceEquals(obj, null))
        {
            throw new Exception();
        }
    }

但这不是:

    private void CheckForNull(object obj)
    {
        if (!ReferenceEquals(obj, null))
        {
            return;
        }
        throw new Exception();
    }

有趣的是,等效代码(由ReSharper:D进行了反转)给出了不同的结果。看起来,模式匹配根本无法实现第二个版本。


6

对于此问题,我的首选解决方案是让resharper认为使用该参数。这比使用属性的优势,比如UsedImplicitly,因为如果你永远 停止使用该参数,ReSharper的将开始再次警告你。如果使用属性,则重新共享也不会捕获将来的实际警告。

使reshaper认为使用了参数的一种简单方法是用throw方法替换。所以代替...

if(myPreconditionParam == wrong)
    throw new Exception(...);

...你写:

if(myPreconditionParam == wrong)
    new Exception(...).ThrowPreconditionViolation();

对于将来的程序员来说,这是很好的自我记录,而harsper不再抱怨。

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;
    }
}

Exception的扩展方法命名空间污染,但它确实包含在内。


提及+1时[UsedImplicitly],我不想使用[AssertionMethod]它,因为在我的情况下,它隐式听起来更准确(我正在将值传递给构造函数中的回调并返回构造的对象)。
MrLore

1

其他人已经回答了这个问题,但是没有人提到以下关闭警告的方法。

在方法签名上方添加以下代码以仅针对该方法将其关闭:

    // ReSharper disable once ParameterOnlyUsedForPreconditionCheck.Local

在类声明上方添加以下代码,以针对整个文件将其关闭:

     // ReSharper disable ParameterOnlyUsedForPreconditionCheck.Local

缺点是您无法指定您所指的女巫参数。
comecme

1
@comecme您可以通过使用禁用和还原 该特定参数的注释来禁用单个参数。在这种情况下,我建议将每个参数放在自己的行上。仍然很丑陋,但不那么(我认为)。
特拉维斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.