【问题标题】:False C# compiler warning?错误的 C# 编译器警告?
【发布时间】:2017-11-01 00:29:00
【问题描述】:

好的,这是我们偶然发现的一个很长的角落案例,但这让我很好奇。

考虑以下代码:

public class Foo
{
    private int foo;
    public int Reset() => foo = 0; //remember, assignment expressions
                                   //return something!
}

这段代码会编译吗?

不,如果您在所有警告中都失败了,则不会;你会收到member foo is assigned but never used 警告。

此代码在所有方面都与以下内容相同:

public class Foo
{
    private int foo;
    public int Reset() { foo = 0; return foo; }
}

哪个编译得很好,那么这里的问题是什么?请注意,=> 语法不是问题,它返回的赋值表达式似乎使编译器感到困惑。

【问题讨论】:

标签: c# compiler-warnings visual-studio-mac


【解决方案1】:

在第一个示例中,分配了foo,但从不读取。 0 被分配给foo,然后返回0,不管foo 的值是什么(例如,如果另一个线程同时改变了它)。

在第二个示例中,分配了foo,然后从中读取。如果另一个线程同时修改了foo,则返回修改后的值,而不是0

您可以通过比较已编译的 IL 来了解这一点。给定以下代码:

public class Foo
{
    private int foo;
    public int Reset() { return (foo = 0); }
    public int Reset2() { foo = 0; return foo; }
}

以下 IL 是为 ResetReset2 编译的。

.method public hidebysig 
    instance int32 Reset () cil managed 
{
    .maxstack 3
    .locals init (
        [0] int32
    )

    IL_0000: ldarg.0
    IL_0001: ldc.i4.0
    IL_0002: dup
    IL_0003: stloc.0
    IL_0004: stfld int32 Foo::foo
    IL_0009: ldloc.0
    IL_000a: ret
}

.method public hidebysig 
    instance int32 Reset2 () cil managed 
{
    .maxstack 8

    IL_0000: ldarg.0
    IL_0001: ldc.i4.0
    IL_0002: stfld int32 Foo::foo
    IL_0007: ldarg.0
    IL_0008: ldfld int32 Foo::foo
    IL_000d: ret
}

Reset,我们只存储到Foo::foo (stfld)。

Reset2 中,您可以看到我们既存储到它又从它加载(stfld + ldfld)。

【讨论】:

【解决方案2】:

用纯 C# 术语回答这个问题,赋值表达式的值就是赋值。我们可以这样证明:

public class Foo
{
    public int Bar
    {
        get { return 2; }
        set { /* do nothing */ }
    }
}

/* … */

Foo foo = new Foo();
Console.WriteLine(foo.Bar = 23);

这会将23 打印到控制台,因为foo.Bar = 23 的值是23,即使foo.Bar 的值始终是2

大多数情况下,这样做的唯一效果是对性能的影响很小,因为大多数情况下,属性或字段的值将是分配给它的值,但我们可以重用我们已经使用的本地值拥有而不是访问该字段的属性。

这里的警告不仅在技术上是正确的,而且也很有用:因为foo 从未真正被读取过,拥有它只是浪费内存和分配时间,您应该将其删除。 (或者,当然,继续开发,以便出现使用它的尚未编码的情况)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多