ReSharper Curiosity: “Parameter hanya digunakan untuk pemeriksaan prakondisi”.

102

Mengapa ReSharper menilai saya untuk kode ini?

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

Metode kedua ValidateCorrespondingValueType parameter "settingValue" berwarna abu-abu dengan pesan berikut oleh ReSharper: "Parameter 'settingValue' hanya digunakan untuk pemeriksaan prakondisi."

Korpsekicker
sumber
Anda dapat memindahkan deklarasi dan tugas exceptionMessageke dalam if-block :)
AakashM
Anda juga bisa melakukan ini dalam metode: expectedText + = ""; dan berhenti mengeluh karena Anda menggunakannya dalam metode ini.
PHPGuru

Jawaban:

104

Itu tidak menghakimi, itu mencoba membantu :)

Jika ReSharper melihat bahwa sebuah parameter hanya digunakan sebagai cek untuk menampilkan pengecualian, itu menjadi abu-abu, menunjukkan bahwa Anda tidak benar-benar menggunakannya untuk pekerjaan "nyata". Ini kemungkinan besar adalah kesalahan - mengapa memasukkan parameter yang tidak akan Anda gunakan? Ini biasanya menunjukkan bahwa Anda telah menggunakannya dalam prasyarat, tetapi kemudian lupa (atau tidak perlu lagi) untuk menggunakannya di tempat lain dalam kode.

Karena metode ini adalah metode pernyataan (artinya, yang dilakukannya hanyalah menegaskan bahwa itu valid), Anda dapat menyembunyikan pesan dengan menandai ValidateCorrespondingValueTypesebagai metode pernyataan, menggunakan atribut anotasi ReSharper , khususnya [AssertionMethod]atribut:

[AssertionMethod]
private void ValidateCorrespondingValueType(SupportedType supportedType, object settingValue)
{
  // …
}
warga negara
sumber
3
Ini adalah cek yang bagus, tetapi dalam kasus ini R # telah melampaui batas sedikit, bukan begitu? Jenis pemeriksaan settingValuetidak mungkin menjadi prakondisi , karena hal yang diperiksa tidak diketahui sampai beberapa pekerjaan telah dilakukan di dalam tubuh metode!
AakashM
6
Itulah mengapa Anda perlu memberi tahu ReSharper bahwa ini adalah metode pernyataan. Satu-satunya poin dari metode ini adalah melakukan pemeriksaan prasyarat untuk metode lain. Ini adalah penegasan, tetapi ReSharper tidak dapat mengetahuinya kecuali Anda memberitahukannya [AssertionMethod].
citizenmatt
10
Saya akhirnya hanya mengubah Keparahan Inspeksi menjadi "Jangan Tunjukkan", ini adalah opsi lain.
reggaeguitar
61
Ini mungkin fitur yang berguna, jika seseorang dapat menonaktifkan pemeriksaan 'prapondisi saja' secara terpisah dari pemeriksaan parameter biasa yang tidak digunakan; seperti berdiri, pemeriksaan mencampur dua masalah dengan tingkat keparahan yang berbeda dan umumnya membuat fungsi ini tidak berguna dalam situasi tertentu. Saya juga sangat skeptis dengan gagasan menambahkan komentar atau atribut ke kode hanya untuk membuat alat analisis kode sumber senang, jadi saat ini saya tidak berpikir ada solusi yang memuaskan untuk masalah ini.
Serge Belov
7
Mungkin mencoba membantu tetapi terlalu agresif. Sekarang, jika Anda memverifikasi nilainya dan kemudian tidak pernah menggunakannya, baiklah, itu mungkin kesalahan. Namun, itu menyalak saya lebih dari satu di mana saya hanya menggunakan nilai dalam kesalahan. Bagaimana lagi itu bisa menjadi sesuatu selain disengaja?
Loren Pechtel
20

Menariknya, ReSharper mundur jika Anda menggunakan nameoffungsionalitas baru di 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));
    }
}
Holf
sumber
3
jawaban ini cocok untuk saya, tidak terlalu mengganggu daripada menambahkan paket
nuget
8

Berikut ini perbaikan masalah (di ReSharper 2016.1.1, VS2015), tetapi saya tidak yakin ini menyelesaikan masalah 'benar'. Bagaimanapun, ini menunjukkan ambiguitas dalam mekanisme ReSharper mengenai topik ini:

Ini menghasilkan peringatan:

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

Tapi ini tidak:

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

Sangat menarik bahwa kode ekivalen (pembalikan dilakukan oleh ReSharper: D) memberikan hasil yang berbeda. Tampaknya pencocokan pola tidak mengambil versi kedua.

Maryn
sumber
6

Solusi yang saya sukai untuk masalah ini adalah membuat resharper berpikir bahwa parameter tersebut digunakan. Ini memiliki keuntungan lebih dengan menggunakan atribut seperti UsedImplicitlykarena jika pernah Anda lakukan berhenti menggunakan parameter itu, resharper akan mulai peringatan Anda lagi. Jika Anda menggunakan atribut, resharper juga tidak akan menangkap peringatan nyata di masa mendatang.

Cara mudah untuk membuat resharper berpikir bahwa parameter yang digunakan adalah dengan menggantinya throwdengan suatu metode. Jadi, bukannya ...

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

...Anda menulis:

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

Ini mendokumentasikan diri sendiri dengan baik untuk programmer masa depan, dan resharper berhenti merengek.

Penerapan ThrowPreconditionViolation itu sepele:

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

Metode ekstensi pada Exception adalah polusi namespace, tetapi cukup berisi.

Eamon Nerbonne
sumber
1 untuk menyebutkan [UsedImplicitly], saya tidak ingin menggunakan [AssertionMethod]sebagaimana adanya, dan digunakan secara implisit terdengar lebih akurat dalam kasus saya (saya mengirimkan nilai ke callback dalam konstruktor dan mengembalikan objek yang dibangun).
MrLore
1

Orang lain telah menjawab pertanyaan itu, tetapi tidak ada yang menyebutkan cara mematikan peringatan berikut.

Tambahkan ini di atas tanda tangan metode untuk mematikannya hanya untuk metode itu:

    // ReSharper disable once ParameterOnlyUsedForPreconditionCheck.Local

Tambahkan ini di atas deklarasi kelas untuk menonaktifkannya untuk seluruh file:

     // ReSharper disable ParameterOnlyUsedForPreconditionCheck.Local
todji
sumber
Kerugiannya adalah Anda tidak dapat menentukan parameter penyihir yang Anda maksud.
comecme
1
@comecme Anda dapat menonaktifkan parameter tunggal dengan menggunakan nonaktifkan dan pulihkan komentar di sekitar parameter tersebut. Saya menyarankan untuk meletakkan setiap parameter pada barisnya sendiri dalam kasus itu; masih jelek tapi kurang begitu (menurut saya).
Travis