非短循环布尔运算符和C#7模式匹配 [英] Non-shortcircuting boolean operators and C# 7 Pattern matching

查看:46
本文介绍了非短循环布尔运算符和C#7模式匹配的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在编写针对.NET 4.7(C#7)的C#应用​​程序.在尝试使用通过"is"关键字声明变量的新方法后,我感到困惑: if(变量为MyClass classInstance)这样就可以了,但是在这样做的时候:

Im currently writing an C# application, targeting .NET 4.7 (C# 7). I am confused after I tried using the new way of declaring a variable utilizing the "is" keyword: if (variable is MyClass classInstance) This way it works, but when doing:

if (true & variable is MyClass classInstance)
{
    var a = classInstance;
}

Visual Studio(我正在使用2017)向我展示了错误的使用未分配的局部变量'classInstance'的错误.使用& (&& )的简短版本可以正常工作.我是否缺少有关& 运算符的信息?(我知道使用短循环版本更为常用,但在这一点上我只是很好奇)

Visual Studio (I'm using 2017) shows me the the Error Use of unassigned local variable 'classInstance'. Using the short-circuting version of & (&&) it works fine. Am I missing something about the & operator? (I know using the shortcircuting versions are much more commonly used, but at this point I'm just curious)

推荐答案

这个伤了我的头,但我想我已经弄清楚了.

This one hurt my head, but I think I have got it figured out.

这种混淆是由两个怪癖引起的: is 操作使变量未声明(不为null)的方式,以及编译器优化布尔运算(而不是按位运算)的方式.

This confusion is caused by two quirks: the way the is operation leaves the variable undeclared (not null), and the way the compiler optimizes away Boolean, but not bitwise, operations.

问题1.如果强制转换失败,则该变量未分配(不为null)

针对新文档是语法:

如果exp为true,并且与if语句一起使用,则为 varname分配,并且仅在if语句内具有局部作用域.

If exp is true and is is used with an if statement, varname is assigned and has local scope within the if statement only.

如果您在两行之间阅读,这意味着如果 is 强制转换失败,则该变量被视为未分配.这可能是违反直觉的(有些人可能希望它是 null ).这意味着,如果整个 if 子句在没有类型匹配的情况下可以评估为 true .例如

If you read between the lines, this means that if the is cast fails, the variable is considered unassigned. This may be counterintuitive (some might expect it to be null instead). This means that any code within the if block that relies on the variable will not compile if there is any chance the overall if clause could evaluate to true without a type match present. So for example

它将编译:

if (instance is MyClass y)
{
    var x = y;
}

然后编译:

if (true && instance is MyClass y)
{
    var x = y;
}

但这不是:

void Test(bool f)
{
    if (f && instance is MyClass y)
    {
        var x = y;  //Error: Use of unassigned local variable
    }
}

Quirk2.优化了布尔运算,而二进制运算则没有优化

当编译器检测到预定的布尔结果时,编译器将不会发出无法访问的代码,并因此跳过某些验证.例如:

When the compiler detects a predestined Boolean result, the compiler will not emit unreachable code, and skips certain validations as a result. For example:

它将编译:

void Test(bool f)
{
    object neverAssigned;
    if (false && f)
    {
        var x = neverAssigned;  //OK (never executes)
    }
}

但是,如果您使用& 而不是&& ,它将无法编译:

But if you use & instead of &&, it does not compile:

void Test(bool f)
{
    object neverAssigned;
    if (false & f)
    {
        var x = neverAssigned;  //Error: Use of unassigned local variable
    }
}

当编译器看到 true& 之类的东西时,它只会完全忽略它.因此

When the compiler sees something like true && it just ignores it completely. Thus

    if (true && instance is MyClass y)

    if (instance is MyClass y)

但这

    if (true & instance is MyClass y)

不一样.编译器仍然需要发出执行& 操作的代码,并在条件语句中使用其输出.或者即使没有,当前的C#7编译器显然也执行相同的验证.这似乎有些奇怪,但是请记住,当您使用& 而不是& 时,可以保证& 必须执行,尽管在此示例中看起来并不重要,但一般情况下必须考虑其他复杂因素,例如运算符重载.

Is NOT the same. The compiler still needs to emit code that performs the & operation and uses its output in a conditional statement. Or even if it doesn't, the current C# 7 compiler apparently performs the same validations as if it were. This may seem a little strange, but bear in mind that when you use & instead of &&, there is a guarantee that the & must execute, and though it seems unimportant in this example, the general case must allow for additional complexifying factors, such as operator overloading.

古怪的组合方式

在最后一个示例中, if 子句的结果是在运行时而不是编译时确定的.因此,编译器无法确定 y 在执行 if 块的内容之前是否最终会被分配.这样你得到

In the last example, the result of the if clause is determined at run time, not compile time. So the compiler can't be certain that y will end up being assigned before the contents of the if block are executed. Thus you get

    if (true & instance is MyClass y)
    {
        var x = y; //Error: use of unassigned local variable
    }

TLDR

在复合逻辑运算的情况下,如果且仅当强制转换成功时,c#不能确定整体 if 条件是否将解析为true.缺乏确定性,它不允许访问该变量,因为它可能是未分配的.当可以在编译时将表达式简化为非复合运算时(例如,通过删除 true&& .

In the situation of a compound logical operation, c# can't be sure that the overall if condition will resolve to true if and only if the cast is successful. Absent that certainty, it can't allow access to the variable, since it might be unassigned. An exception is made when the expression can be reduced to non-compound operation at compile time, for example by removing true &&.

解决方法

我认为我们使用新的 is 语法的方式是带有 if 子句的单个条件.一开始添加 true& 的方法是可行的,因为编译器只是将其删除.但是,其他任何与新语法结合使用的方法,都将导致在代码块运行时新变量是否处于未分配状态的歧义,并且编译器不允许这样做.

I think the way we are meant to use the new is syntax is as a single condition with an if clause. Adding true && at the beginning works because the compiler simply removes it. But anything else combined with the new syntax creates ambiguity about whether the new variable will be in an unassigned state when the code block runs, and the compiler can't allow that.

解决方法当然是嵌套您的条件,而不是合并它们:

The workaround of course is to nest your conditions instead of combining them:

不起作用:

void Test(bool f)
{
    if (f & instance is MyClass y)
    {
        var x = y;  //Error: Use of unassigned local variable
    }
}

工作正常:

void Test(bool f)
{
    if (f)
    {
        if (instance is MyClass y)
        {
            var x = y;  //Works
        }
    }
}

这篇关于非短循环布尔运算符和C#7模式匹配的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆