return myVar와 return (myVar) 사이에 차이점이 있습니까?


87

몇 가지 예제 C # 코드를 살펴본 결과 한 예제가 ()에 반환을 래핑하는 것을 알았습니다.

나는 항상 그랬다.

return myRV;

차이가 있습니까?

return (myRV);

답변:


229

업데이트 :이 질문은 2010 년 4 월 12 일 제 블로그의 주제였습니다 . 재미있는 질문에 감사드립니다!

실제로는 차이가 없습니다.

이론 차이가있을 수 있습니다. C # 사양에는 이것이 차이를 나타낼 수있는 세 가지 흥미로운 점이 있습니다.

첫째, 익명 함수를 대리자 형식 및 식 트리로 변환합니다. 다음을 고려하세요:

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에서 열거 된 유형으로의 변환이 있다고 명시되어 있습니다. " (0)"은 리터럴 0이 아니며 괄호 뒤에 리터럴 0, 괄호가 이어집니다. 여기서 사양을 위반하고 실제로 리터럴 0뿐만 아니라 0과 같은 컴파일 시간 상수 표현식을 허용합니다 .

따라서 모든 경우에 우리는 기술적으로 불법이더라도 당신이 그것을 피할 수 있도록 허용합니다.


12
@Jason : 처음 두 경우의 사양 위반은 단순히 발견되지 않은 오류라고 생각합니다. 역사적으로 초기 바인딩 패스는 식을 조기에 최적화하는 데 매우 공격적이었으며 그 결과 중 하나는 괄호가 예상보다 빨리 아주 일찍 버려진다는 것입니다. 거의 모든 경우에이 모든 작업은 직관적으로 명백한 프로그램이 원하는 방식으로 작동하도록 만드는 것이므로 그다지 걱정하지 않습니다. 세 번째 사례 분석 : blogs.msdn.com/ericlippert/archive/2006/03/28/…
Eric Lippert

6
이론적으로, 실제로 거기에 있다 차이 (I 모노는이 3 건 수 있는지 경우 아니에요, 및 기타의 C # 컴파일러의 모르는, 그래서 나 연습에 연습에 차이가 없을 수도 있습니다)가. C # 사양을 위반하면 코드를 완전히 이식 할 수 없습니다. 일부 C # 컴파일러는 Visual C #과 달리 특정 경우에 사양을 위반하지 않을 수 있습니다.
Brian

18
@Bruno : 주어진 주제에 대해 약 8 ~ 10,000 시간의 연구가 필요하며 당신도 그것에 대한 전문가가 될 수 있습니다. 4 년 동안 풀 타임으로 일하면 쉽게 할 수 있습니다.
Eric Lippert

32
@Anthony : 제가 그렇게 할 때 저는 사람들에게 제 학위가 산술이 아니라 수학에 있다고 말합니다 .
Eric Lippert

7
이론적으로는 실천과 이론은 같지만, 실제로는 그렇지 않습니다.
Sayed Ibrahim Hashimi

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

삼.

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

실제로는 이것을 결코 볼 수 없기를 바랍니다.


내 질문에 대한 답은 아니지만 여전히 흥미 롭습니다. 감사합니다.
chris

1
여기 2에서 무슨 일이 일어나고 있는지 설명해 주시겠습니까?
에릭

2
이 동작이 발생하는 이유를 자세히 설명해야합니다.
Arturo Torres Sánchez


3

이와 같은 질문에 답하는 좋은 방법은 Reflector를 사용하여 IL이 생성되는 것을 확인하는 것입니다. 어셈블리를 디 컴파일하여 컴파일러 최적화 등에 대해 많은 것을 배울 수 있습니다.


6
그것은 하나의 특정한 경우에 대한 질문에 확실히 대답 할 것이지만, 그것이 반드시 전체 상황을 대표하는 것은 아닙니다.
Beska 2010

동의하지 않는다. 그것은 그 사람에게 질문에 답할 방향을줍니다.
Bryan
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.