Apakah ada perbedaan antara return myVar vs. return (myVar)?

87

Saya melihat beberapa contoh kode C #, dan memperhatikan bahwa satu contoh membungkus return in ().

Saya selalu baru saja selesai:

return myRV;

Apakah ada perbedaan melakukan:

return (myRV);
chris
sumber

Jawaban:

229

PEMBARUAN: Pertanyaan ini adalah subjek blog saya pada 12 April 2010 . Terima kasih atas pertanyaannya yang lucu!

Dalam prakteknya tidak ada perbedaan.

Secara teori mungkin ada perbedaan. Ada tiga poin menarik dalam spesifikasi C # yang bisa menghadirkan perbedaan.

Pertama, konversi fungsi anonim menjadi tipe delegasi dan pohon ekspresi. Pertimbangkan yang berikut ini:

Func<int> F1() { return ()=>1; }
Func<int> F2() { return (()=>1); }

F1jelas legal. Apakah F2? Secara teknis, tidak. Spesifikasi mengatakan di bagian 6.5 bahwa ada konversi dari ekspresi lambda ke tipe delegasi yang kompatibel. Apakah itu ekspresi lambda ? Tidak. Ini adalah ekspresi dalam tanda kurung yang berisi ekspresi lambda .

Kompiler Visual C # membuat pelanggaran spesifikasi kecil di sini dan membuang tanda kurung untuk Anda.

Kedua:

int M() { return 1; }
Func<int> F3() { return M; }
Func<int> F4() { return (M); }

F3adalah legal. Apakah F4? Tidak. Bagian 7.5.3 menyatakan bahwa ekspresi dalam tanda kurung tidak boleh berisi grup metode. Sekali lagi, demi kenyamanan Anda, kami melanggar spesifikasi dan mengizinkan konversi.

Ketiga:

enum E { None }
E F5() { return 0; }
E F6() { return (0); }

F5adalah legal. Apakah F6? Tidak. Spesifikasi menyatakan bahwa ada konversi dari nol literal ke jenis yang disebutkan. " (0)" bukan nol literal, ini adalah tanda kurung yang diikuti oleh nol literal, diikuti dengan tanda kurung. Kami melanggar spesifikasi di sini dan sebenarnya mengizinkan ekspresi konstanta waktu kompilasi apa pun yang sama dengan nol , dan bukan hanya nol literal.

Jadi, dalam setiap kasus, kami mengizinkan Anda untuk lolos, meskipun secara teknis melakukannya adalah ilegal.

Eric Lippert
sumber
12
@Jason: Saya yakin pelanggaran spesifikasi dalam dua kasus pertama hanyalah kesalahan yang tidak pernah tertangkap. Pengikatan awal secara historis sangat agresif tentang pengoptimalan ekspresi sebelum waktunya, dan salah satu konsekuensinya adalah tanda kurung dibuang lebih awal, lebih awal dari yang seharusnya. Dalam hampir setiap kasus, semua ini dilakukan adalah membuat program yang secara intuitif bekerja jelas sebagaimana mestinya, jadi saya tidak terlalu khawatir tentang itu. Analisis kasus ketiga ada di sini: blogs.msdn.com/ericlippert/archive/2006/03/28/…
Eric Lippert
6
Dalam teori, dalam prakteknya, ada adalah perbedaan (Saya tidak yakin apakah Mono memungkinkan 3 kasus ini, dan tidak tahu dari setiap C # compiler lain, sehingga mungkin atau mungkin tidak ada perbedaan dalam praktek dalam praktek). Melanggar spesifikasi C # berarti kode Anda tidak akan sepenuhnya portabel. Beberapa kompiler C # mungkin, tidak seperti Visual C #, tidak melanggar spesifikasi dalam kasus tersebut.
Brian
18
@Bruno: Yang dibutuhkan adalah sekitar delapan atau sepuluh ribu jam untuk mempelajari subjek tertentu dan Anda juga bisa menjadi ahli di dalamnya. Itu mudah dilakukan dalam empat tahun kerja penuh waktu.
Eric Lippert
32
@Anthony: Ketika saya melakukannya, saya hanya memberi tahu orang-orang bahwa gelar saya di bidang matematika , bukan aritmatika .
Eric Lippert
7
Secara teori, praktek dan teori adalah sama tetapi dalam prakteknya tidak pernah sama.
Sayed Ibrahim Hashimi
40

Ada kasus sudut ketika kehadiran tanda kurung dapat mempengaruhi perilaku program:

1.

using System;

class A
{
    static void Foo(string x, Action<Action> y) { Console.WriteLine(1); }
    static void Foo(object x, Func<Func<int>, int> y) { Console.WriteLine(2); }

    static void Main()
    {
        Foo(null, x => x()); // Prints 1
        Foo(null, x => (x())); // Prints 2
    }
}

2.

using System;

class A
{
    public A Select(Func<A, A> f)
    {
        Console.WriteLine(1);
        return new A();
    }

    public A Where(Func<A, bool> f)
    {
        return new A();
    }

    static void Main()
    {
        object x;
        x = from y in new A() where true select (y); // Prints 1
        x = from y in new A() where true select y; // Prints nothing
    }
}

3.

using System;

class Program
{
    static void Main()
    {
        Bar(x => (x).Foo(), ""); // Prints 1
        Bar(x => ((x).Foo)(), ""); // Prints 2
    }

    static void Bar(Action<C<int>> x, string y) { Console.WriteLine(1); }
    static void Bar(Action<C<Action>> x, object y) { Console.WriteLine(2); }
}

static class B
{
    public static void Foo(this object x) { }
}

class C<T>
{
    public T Foo;
}

Semoga Anda tidak akan pernah melihat ini dalam praktiknya.

Vladimir Reshetnikov
sumber
Bukan jawaban untuk pertanyaan saya, tapi tetap menarik - terima kasih.
chris
1
Bisakah Anda menjelaskan apa yang terjadi dalam 2 di sini?
Eric
2
Anda harus menjelaskan mengapa perilaku ini terjadi.
Arturo Torres Sánchez
26

Tidak, tidak ada perbedaan selain sintaksis.

JaredPar
sumber
3

Cara yang baik untuk menjawab pertanyaan seperti ini adalah dengan menggunakan Reflector dan melihat IL apa yang dihasilkan. Anda bisa belajar banyak tentang pengoptimalan compiler dan semacamnya dengan mendekompilasi assemblies.

Bryan
sumber
6
Itu pasti akan menjawab pertanyaan untuk satu kasus tertentu, tapi itu belum tentu mewakili keseluruhan situasi.
Beska
Tidak setuju. Ini memberi orang itu arahan untuk menjawab pertanyaan.
Bryan