return myVar与return(myVar)之间有区别吗?


87

我在看一些示例C#代码,并注意到一个示例将返回值包装在()中。

我一直都做:

return myRV;

这样做有什么区别吗?

return (myRV);

Answers:


229

更新:这个问题是我2010年4月12日博客的主题。感谢您提出有趣的问题!

实际上,没有区别。

理论上讲可能有所不同。C#规范中有三个有趣的地方,它们可能会有所不同。

首先,将匿名函数转换为委托类型和表达式树。考虑以下:

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

F1显然是合法的。是F2吗 从技术上讲,没有。规范在6.5节中说,存在从lambda表达式到兼容委托类型的转换。那是lambda表达式吗?不。这是一个带括号的表达式,其中包含lambda表达式

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
@Jason:我相信前两个案例中的规范违规只是从未发现的错误。从历史上看,初始绑定过程对于过早优化表达式一直非常激进,其后果之一是括号被抛弃的时间非常早,早于其应有的时间。在几乎每种情况下,所有这些操作都是使程序在其直观上显而易见的方式按应有的方式工作,因此我对此并不十分担心。第三种情况的分析如下:blogs.msdn.com/ericlippert/archive/2006/03/28/…–
埃里克·利珀特

6
从理论上讲,在实践中存在差别(我不知道,如果单让这3个的情况下,不知道任何其他C#编译器,所以有可能会或可能不会在实践中实际上的差别)。违反C#规范意味着您的代码将无法完全移植。与Visual C#不同,某些C#编译器在某些特定情况下可能不会违反规范。
布赖恩2010年

18
@布鲁诺:只需要花费大约八,一万小时的时间就可以学习给定的主题,您也可以成为该领域的专家。在四年的全职工作中,这很容易做到。
埃里克·利珀特

32
@Anthony:这样做的时候,我只是告诉人们我的学位是数学,而不是算术
埃里克·利珀特

7
在理论上,实践和理论是相同的,但实际上,它们从来都不是。
易卜拉欣(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
    }
}

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

希望您在实践中永远不会看到这一点。


并非完全是我的问题的答案,但仍然很有趣-谢谢。
克里斯,2010年

1
您能解释一下这里2发生了什么吗?
埃里克

2
您应该详细说明为什么会发生这种现象。
Arturo TorresSánchez2015年


3

回答此类问题的一种好方法是使用Reflector并查看生成了什么IL。您可以通过反汇编程序集学习有关编译器优化的很多知识。


6
这肯定会回答一个特定案例的问题,但这并不一定代表整个情况。
Beska

不同意。它给人指导回答问题的方向。
布赖恩2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.