模式匹配动态变量导致的编译器错误

问题描述

为什么将 c != null && 结果添加c1 的编译器错误 CS0165?目标是.NET5.0。

var a = "";
if(a is string a1)
{
    if("".Contains(a1)) return; //OK
}
dynamic b = "";
if(b is string b1)
{
    if("".Contains(b1)) return; //OK
}

dynamic c = "";
if(c != null && c is string c1)
{
    if("".Contains(c1)) return; //CS0165 Using not assigned variable??
}

dynamic d = "";
if(d != null && d is string)
{
    var d1 = d;
    if("".Contains(d1)) return; //OK

    var d11 = d as string;
    if("".Contains(d11)) return; //OK
}

更新:
所以根据Luaan的回答,整个语句不会被评估,不仅在动态对象的右侧

dynamic d = "";
var c = "";
if(c is string c1 && true && d != null && c is string f1)
{
    if("".Contains(c1)) return; //error
                
    if("".Contains(f1)) return; //error

    var d1 = d;
    if("".Contains(d1)) return; //OK
    var d11 = d as string;
    if("".Contains(d11)) return; //OK
}

解决方法

&& 不会在编译时对动态操作数短路。

根据规范 (Conditional logical operators):

如果条件逻辑运算符的操作数具有编译时类型 dynamic,则表达式是动态绑定的(动态绑定)。在这种情况下,表达式的编译时类型是动态的,下面描述的解析将在运行时使用那些具有编译时类型动态的操作数的运行时类型进行。

c != null && c is string c1 是动态表达式,所以是动态绑定的,静态编译器不能保证 c1 被赋值。

当然,这在实践中并不重要,因为您的空检查完全是多余的 - is string 已经确保该值不为空。

,

这里的问题是编译器无法以任何方式验证逻辑运算符没有以某种奇怪的方式重载,这种方式碰巧从不计算逻辑表达式的右侧,同时仍然成功返回 true。这就是您收到编译时错误的原因。