为什么这段代码不可达?

Mic*_*ito 49 .net c# unreachable-code

我发现了一个案例,我有一些我认为无法访问且未被检测到的代码.编译器和Visual Studio都不会发出警告.

考虑以下代码:

enum Foo { A, B, C }
class Bar { public Foo type; }

static class Program
{
    private static void Main()
    {
        var bar = new Bar { type = Foo.A };

        if (bar.type == Foo.B)
        {
            Console.WriteLine("lol");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

显然,程序不会打印出"lol",因为if语句中的条件为false.我不明白为什么没有为无法访问的代码发出警告.我唯一的假设是,如果你在多线程程序中遇到竞争条件,那么这可能是可以达到的.它是否正确?

Avn*_*tan 133

静态分析只能做很多事情,如果能证明代码无法更改,它只会将代码标记为无法访问.在您的代码中,内部发生的事情Bar超出了方法流程的范围,无法进行静态推理.如果Bar构造函数启动一个设置type返回值的线程B怎么办?编译器无法知道它,因为再次,内部Bar结构不是作用于方法的.

如果您的代码正在检查局部变量的值,那么编译器可以知道它是否无法更改.但事实并非如此.

  • "静态分析只能做很多事情",即大多数(有用的)静态分析是合理但不完整的 - 即它不能保证推断出程序的所有属性,只是它所做的*推断是真的.推断*程序的所有*属性(包括它们是否停止或其变化)被证明是不可判定的,我们*喜欢*我们的编辑器可能无限期地悬挂,对吧? (29认同)
  • 例如,ReSharper添加了编译器没有的各种分析和警告.像关于可能意外的相互递归或可能的堆栈溢出异常的警告.但是它们明显标记并与编译器输出分开 (2认同)

Raw*_*ing 27

C#规范说,

如果if语句可以访问且布尔表达式没有常量值false,则可以访问if语句的第一个嵌入语句.

并且,关于常数表达式,

常量表达式必须是null文本或与以下类型之一的值:为sbyte,字节,短,USHORT,INT,UINT,长,ULONG,炭,浮点,双精度,小数,布尔,对象,字符串或任何枚举类型.

在常量表达式中只允许以下构造:

  • 文字(包括null文字).
  • 对类和结构类型的const成员的引用.
  • 引用枚举类型的成员.
  • 对const参数或局部变量的引用
  • 带括号的子表达式,它们本身是常量表达式.
  • 如果目标类型是上面列出的类型之一,则转换表达式.选中和未选中的表达式
  • 默认值表达式
  • 预定义的+,,!,和~一元运算符.
  • 预定义的+,,*,/,%,<<,>>,&,|, ,^,&&,||,==,!=,<,>,<=>=的二进制运算符,提供的每个操作数是上面列出的类型.
  • ?:有条件的经营者.

成员访问表达式不在此列表中,因此布尔表达式不是常量.因此if块的主体是可达的.

  • 对于那些好奇的人,提到"const参数"是[规范中的一个错误](https://twitter.com/gafter/status/961799472538828801).C#没有它们. (2认同)

Iva*_*ich 9

因为在编译时不能做出这样的保证.考虑这个替代Bar类

class Bar
{
   Random random = new Random();
   Array Foos = Enum.GetValues(typeof(Foo));

    private Foo _type;
    public Foo type
    {
        get { return _type; }
        set
        {
            _type = (Foo)Foos.GetValue(random.Next(3));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,"可达"是在功能级别定义的.即使在安全的情况下,也不允许到达正在测试的功能之外.

  • 唉,这不是另一种Bar类,因为你将`Bar.type`从一个字段改为一个属性,一个完全不同的动物. (2认同)