为什么可以为空的模式匹配会导致语法错误?

时间:2018-01-19 14:09:47

标签: c# pattern-matching nullable c#-7.0

我想在pattern-matching上使用nullable int,即int?

int t  = 42;
object tobj = t;    
if (tobj is int? i)
{
    System.Console.WriteLine($"It is a nullable int of value {i}");
}

但是,这会导致以下语法错误:

'i)'标有红色波浪线。

使用旧操作符is时表达式编译:

int t = 42;
object tobj = t;    
if (tobj is int?)
{
    System.Console.WriteLine($"It is a nullable int");
}


string t = "fourty two";
object tobj = t;
if (tobj is string s)
{
    System.Console.WriteLine($@"It is a string of value ""{s}"".");
}

也按预期工作。

(我正在使用并使用进行测试

我认为它与运营商优先级有关。因此,我尝试在几个地方使用括号,但这没有帮助。

为什么会出现这些语法错误,如何避免这些错误呢?

3 个答案:

答案 0 :(得分:15)

各种形式的类型模式:x is T ycase T y等,always fails to match when x is null。这是因为null doesn't have a type,所以问“这是这种null吗?”是一个毫无意义的问题。

因此,t is int? it is Nullable<int> i作为一种模式毫无意义:tint,在这种情况下,t is int i无论如何都会匹配,或者它是null,在这种情况下,任何类型模式都不会导致匹配。

这就是为什么t is int? it is Nullable<int> i不是,也可能永远不会被编译器支持的原因。

在使用t is int? i时,您从编译器获得其他错误的原因是,例如, t is int? "it's an int" : "no int here"是有效的语法,因此编译器会对您在此上下文中使用?作为可空类型的尝试感到困惑。

至于如何避免它们,明显(尽管可能不是很有帮助)的答案是:不要使用可空类型作为类型模式中的类型。一个更有用的答案需要你解释为什么你试图这样做。

答案 1 :(得分:3)

对于任何想知道如何将模式匹配与nullable实际结合使用的人,可以使用通用的辅助函数来实现,例如:

public static bool TryConvert<T>(object input, out T output)
{
    if (input is T result)
    {
        output = result;
        return true;
    }
    output = default(T);
    // Check if input is null and T is a nullable type.
    return input == null && System.Nullable.GetUnderlyingType(typeof(T)) != null;
}

如果true是与T包含的类型相同的可空值或不可空值,或者input为空且input,则返回T为空。基本上和普通的一样,但是也可以处理可空值。


旁注:有趣的是,从我的测试中,我发现System.Nullable.GetUnderlyingType(typeof(T))在T可以为空时每次调用时分配40个字节的垃圾。不知道为什么,对我来说似乎是个错误,但这可能是要付出的高昂代价,而不是像通常那样仅进行空检查。

知道这一点,这是一个更好的功能:

public static bool TryConvert<T>(object input, out T? output) where T : struct
{
    if (input is T result)
    {
        output = result;
        return true;
    }
    output = default(T?);
    return input == null;
}

答案 2 :(得分:2)

将您的代码更改为:

int t = 42;
object tobj = t;
if (tobj is Nullable<int> i)
{
    Console.WriteLine($"It is a nullable int of value {i}");
}

这会产生更多帮助:

  • CS8116:使用可空类型'int?'是不合法的在一个模式;使用基础类型'int'而不是 (找不到关于CS8116的文档来引用)

其他人(用户@Blue0500 at github)已将此行为标记为错误Roslyn issue #20156。对微软的Roslyn issue #20156Julien Couvreur做出反应,他说他认为这是设计的 微软致力于Roslyn的Neal Gafter也说better diagnostics are wanted for use of nullable type is switch pattern

因此,使用以下命令可以避免错误消息:

int t = 42;
object tobj = t;
if (tobj == null)
{
    Console.WriteLine($"It is null");
}
else if (tobj is int i)
{
    Console.WriteLine($"It is a int of value {i}");
}

除了issues when parsing tobj is int? i之外,这仍然存在为什么tobj is int? itobj is Nullable<int> i不被允许的问题。