ReSharper Curiosity:“ พารามิเตอร์ใช้สำหรับการตรวจสอบเงื่อนไขเบื้องต้นเท่านั้น”


104

ทำไม 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);
        }
    }

วิธีที่สองพารามิเตอร์ "settingValue" ของ ValidateCorrespondingValueType เป็นสีเทาพร้อมข้อความต่อไปนี้โดย ReSharper: "พารามิเตอร์" settingValue "ใช้สำหรับการตรวจสอบเงื่อนไขเบื้องต้นเท่านั้น"


คุณสามารถย้ายการประกาศและการมอบหมายexceptionMessageไปที่if-block :)
AakashM

คุณสามารถทำได้ด้วยวิธีนี้: expectedText + = ""; และหยุดบ่นตั้งแต่คุณใช้วิธีนี้
PHPGuru

คำตอบ:


106

ไม่ได้ตัดสิน แต่พยายามช่วย :)

หาก ReSharper เห็นว่ามีการใช้พารามิเตอร์เป็นเช็คเพื่อโยนข้อยกเว้นเท่านั้นพารามิเตอร์นั้นจะเป็นสีเทาแสดงว่าคุณไม่ได้ใช้พารามิเตอร์นี้สำหรับงาน "จริง" จริงๆ นี่อาจเป็นข้อผิดพลาด - ทำไมต้องส่งพารามิเตอร์ที่คุณจะไม่ใช้? โดยปกติจะระบุว่าคุณเคยใช้งานในสภาพก่อน แต่ลืมไปแล้ว (หรือไม่จำเป็นต้องใช้อีกต่อไป) เพื่อใช้ที่อื่นในรหัส

เนื่องจากวิธีนี้เป็นวิธีการยืนยัน (นั่นคือทั้งหมดที่ทำก็คือยืนยันว่าถูกต้อง) คุณสามารถระงับข้อความโดยทำเครื่องหมายValidateCorrespondingValueTypeเป็นวิธีการยืนยันโดยใช้แอตทริบิวต์คำอธิบายประกอบของ ReSharper โดยเฉพาะ[AssertionMethod]แอตทริบิวต์:

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

3
เป็นการตรวจสอบที่ดี แต่ในกรณีนี้ R # เกินไปเล็กน้อยคุณจะไม่พูด? ประเภทของการตรวจสอบsettingValueไม่สามารถเป็นเงื่อนไขล่วงหน้าได้เนื่องจากไม่ทราบสิ่งที่จะตรวจสอบจนกว่าจะมีการทำงานบางอย่างภายในเนื้อความของวิธีการ!
AakashM

6
นั่นเป็นเหตุผลที่คุณต้องบอก ReSharper ว่าเป็นวิธีการยืนยัน จุดเดียวของวิธีนี้คือการตรวจสอบเงื่อนไขล่วงหน้าสำหรับวิธีอื่น มันเป็นยืนยัน แต่ ReSharper [AssertionMethod]ไม่สามารถรู้ได้ว่าถ้าคุณบอกมันด้วย
citizenmatt

10
ฉันเพิ่งเปลี่ยนความรุนแรงในการตรวจสอบเป็น "ไม่แสดง" นี่เป็นอีกทางเลือกหนึ่ง
reggaeguitar

62
อาจเป็นคุณสมบัติที่มีประโยชน์หากสามารถปิดใช้งานการตรวจสอบ 'เงื่อนไขล่วงหน้าเท่านั้น' โดยไม่ขึ้นอยู่กับการตรวจสอบพารามิเตอร์ปกติที่ไม่ได้ใช้ ตามที่ระบุไว้การตรวจสอบเป็นการผสมผสานปัญหาสองประเด็นที่มีความรุนแรงแตกต่างกันและโดยทั่วไปทำให้ฟังก์ชันนี้ไม่มีประโยชน์ในบางสถานการณ์ ฉันยังสงสัยมากเกี่ยวกับแนวคิดในการเพิ่มความคิดเห็นหรือแอตทริบิวต์ให้กับโค้ดเพียงเพื่อให้เครื่องมือวิเคราะห์ซอร์สโค้ดมีความสุขดังนั้นในขณะนี้ฉันไม่คิดว่าจะมีวิธีแก้ปัญหาที่น่าพอใจ
Serge Belov

7
อาจพยายามช่วย แต่ก้าวร้าวเกินไป ตอนนี้หากคุณตรวจสอบค่าแล้วไม่เคยใช้เลยนั่นอาจเป็นข้อผิดพลาด อย่างไรก็ตามมันกำลังเยาะใส่ฉันมากกว่าหนึ่งที่ฉันใช้ค่าในข้อผิดพลาดเท่านั้น จะเป็นอย่างอื่นไปได้อย่างไรนอกจากเจตนา?
Loren Pechtel

21

ที่น่าสนใจคือ ReSharper จะปิดการใช้งานหากคุณใช้nameofฟังก์ชันใหม่ใน C # 6:

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

    if (logger == null)
    {
        throw new ArgumentNullException(nameof(logger));
    }
}

3
คำตอบนี้เหมาะกับฉันมันล่วงล้ำน้อยกว่าการเพิ่มแพ็คเกจนักเก็ต
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 จะเริ่มเตือนคุณอีกครั้ง หากคุณใช้แอตทริบิวต์ resharper จะไม่ได้รับคำเตือนจริงในอนาคตเช่นกัน

วิธีง่ายๆในการทำให้ resharper คิดว่าใช้พารามิเตอร์คือการแทนที่throwด้วยวิธีการ ดังนั้นแทนที่จะ ...

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

...ที่คุณเขียน:

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

นี่เป็นเอกสารในตัวเองสำหรับโปรแกรมเมอร์ในอนาคตและ 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;
    }
}

วิธีการขยายข้อยกเว้นคือเนมสเปซมลพิษ แต่มีอยู่พอสมควร


+1 สำหรับการกล่าวถึง[UsedImplicitly]ฉันไม่ต้องการใช้[AssertionMethod]เพราะมันไม่ใช่และใช้โดยนัยฟังดูแม่นยำกว่าในกรณีของฉัน (ฉันกำลังส่งค่าไปยังการเรียกกลับในตัวสร้างและส่งคืนวัตถุที่สร้างขึ้น)
MrLore

2

คนอื่น ๆ ได้ตอบคำถามแล้ว แต่ไม่มีใครพูดถึงวิธีการปิดคำเตือนต่อไปนี้

เพิ่มสิ่งนี้เหนือลายเซ็นวิธีการเพื่อปิดสำหรับวิธีนั้นเท่านั้น:

    // ReSharper disable once ParameterOnlyUsedForPreconditionCheck.Local

เพิ่มสิ่งนี้เหนือการประกาศคลาสเพื่อปิดสำหรับทั้งไฟล์:

     // ReSharper disable ParameterOnlyUsedForPreconditionCheck.Local

1
ข้อเสียคือคุณไม่สามารถระบุพารามิเตอร์แม่มดที่คุณหมายถึงได้
comecme

1
@comecme คุณสามารถปิดใช้งานสำหรับพารามิเตอร์เดียวได้โดยใช้ปิดใช้งานและเรียกคืน ความคิดเห็นเกี่ยวกับพารามิเตอร์นั้น ๆ ฉันขอแนะนำให้ใส่ทุกพารามิเตอร์ในบรรทัดของตัวเองในกรณีนั้น ยังน่าเกลียด แต่น้อยกว่านั้น (ในความคิดของฉัน)
Travis
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.