return myVarとreturn(myVar)に違いはありますか?


87

私はいくつかのC#コードの例を見ていましたが、1つの例が戻り値を()でラップしていることに気付きました。

私はいつもやっただけです:

return myRV;

違いはありますか?

return (myRV);

回答:


229

更新:この質問は2010年4月12日の私のブログの主題でした。面白い質問をありがとう!

実際には違いはありません。

では理論の違いがある可能性があります。C#仕様には、これが違いをもたらす可能性のある3つの興味深い点があります。

まず、匿名関数からデリゲート型および式ツリーへの変換。以下を検討してください。

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

F1明らかに合法です。ですかF2?技術的には違います。仕様はセクション6.5でラムダ式から互換性のあるデリゲート型への変換があると述べています。それはラムダ式ですか?いいえ。これは、ラムダ式を含む括弧付きの式です。

Visual C#コンパイラはここで小さな仕様違反を起こし、かっこを破棄します。

第二:

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

F3合法です。ですかF4?いいえ。セクション7.5.3では、括弧で囲まれた式にはメソッドグループを含めることができないと記載されています。繰り返しになりますが、お客様の便宜のため、仕様に違反しており、変換を許可しています。

第三:

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

F5合法です。ですかF6?いいえ。仕様では、リテラルのゼロから任意の列挙型への変換があると述べています。「(0)」はリテラルのゼロではなく、括弧の後にリテラルのゼロが続き、その後に括弧が続きます。ここでは仕様に違反しているため、実際のリテラルゼロではなく、ゼロ等しいコンパイル時定数式を実際に許可しています

したがって、技術的にそうすることは違法ですが、どの場合でも、私たちはあなたがそれを回避することを許可します。


12
@ジェイソン:最初の2つのケースでの仕様違反は、単にキャッチされなかったエラーであると私は信じています。初期のバインディングパスは、歴史的に、式の時期尚早な最適化について非常に積極的でした。その結果の1つは、括弧が本来あるべきよりも早く、非常に早く捨てられることです。ほぼすべての場合で、これは、直感的に明らかなプログラムを本来の方法で動作させることになるため、あまり心配していません。第三例の分析はここにある:blogs.msdn.com/ericlippert/archive/2006/03/28/...
エリックリペット

6
理論的には、実際に違いあります(Monoがこれらの3つのケースを許可するかどうかはわかりません。他のC#コンパイラも知らないため、実際には実際に違いがあるかどうかはわかりません)。C#仕様に違反すると、コードを完全に移植できなくなります。一部のC#コンパイラは、Visual C#とは異なり、これらの特定のケースでは仕様に違反しない場合があります。
ブライアン

18
@Bruno:必要なのは、特定の主題について約8時間または1万時間勉強することだけであり、あなたもその専門家になれます。これは4年間のフルタイムの仕事で簡単に実行できます。
Eric Lippert、2010

32
@Anthony:私はちょうど私の度合いが中であることを人々に伝えることを行う数学ではなく、算術
エリックリッペルト2010

7
理論的には、実践と理論は同じですが、実際にはそうではありません。
イブラヒム・ハシミ

40

括弧の存在がプログラムの動作に影響を与える可能性のある、まれなケースがあります。

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

実際にはこれが表示されないことを願っています。


私の質問に対する正確な回答ではありませんが、それでも興味深いです-ありがとう。
クリス

1
ここで2で何が起こっているのか説明できますか?
Eric

2
この動作が発生する理由を詳しく説明する必要があります。
Arturo TorresSánchez15年


3

このような質問に答える良い方法は、Reflectorを使用して、ILが生成されるものを確認することです。アセンブリを逆コンパイルすることにより、コンパイラの最適化などについて多くを学ぶことができます。


6
それは確かに1つの特定のケースの質問に答えますが、それは必ずしも状況全体を表すものではありません。
Beska

同意しない。それは人に質問に答える方向を与えます。
ブライアン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.