我可以在动态构造的本地元组上使用模式匹配吗?

问题描述 投票:0回答:1

此示例代码无法编译:

record Thing(List<int> xs, List<int> ys);

    int DoStuff(Thing thing)
    {
        return (thing.xs, thing.ys) switch
        {
            xs.Count > 5 => xs.First(),
            ys.Count > 5 => ys.Last(),
            xs.Count + ys.Count > 5 => xs.First()+ys.Last(),
            (xs.Count > 0, ys.Count > 0) => Math.Max(xs.First(),ys.Last()),
            _ => -1
        }; 
    }

C#(.Net 6 或 .Net 7)是否提供了一种语法来执行我在这里尝试的操作,或者这是否将模式匹配语法推得太远了?

我以为我可以使用

{}
语法(关系模式?)但是这仍然不起作用,因为捕获返回值是脱离上下文的。

return (thing.xs, thing.ys) switch
{
    {xs.Count: > 5} => xs.First(),
    {ys.Count: > 5} => ys.Last(),
    {xs.Count + ys.Count: > 5} => xs.First()+ys.Last(),
    {xs.Count: > 0 , ys.Count: > 0) => Math.Max(xs.First(),ys.Last()),
    _ => -1
}; 

看起来我越来越接近了,但只是在没有真正理解语言语法的情况下反复试验。

c# .net pattern-matching
1个回答
1
投票

您可以打开包含计数的元组并使用元组模式。 (我将

as
bs
重命名为
a
b
因为
as
是保留关键字):

int DoStuff(Thing thing)
{
    return (thing.a.Count, thing.b.Count) switch {
        ( > 5, _) => thing.a.Count,
        (_, > 5) => thing.b.Count,
        _ when thing.a.Count + thing.b.Count > 5 => thing.a.Count + thing.b.Count,
        ( > 0, > 0) => Math.Max(thing.a.Count, thing.b.Count),
        _ => -1
    };
}

注意丢弃

_
的意思是“没关系”。例如,模式
( > 5, _)
表示:元组的第一项 (
thing.a.Count
) 必须大于 5,第二项 (
thing.b.Count
) 无关紧要。也就是说,如果你打开一个元组,你必须使用元组模式。

由于我们不能在模式中使用加法运算,所以我使用了

when
子句来引入标准布尔条件。

这种方法的改进是创建一个命名元组以进一步简化:

int DoStuff(Thing thing)
{
    var t = (ac: thing.a.Count, bc: thing.b.Count);
    return t switch {
        ( > 5, _) => t.ac,
        (_, > 5) => t.bc,
        _ when t.ac + t.bc > 5 => t.ac + t.bc,
        ( > 0, > 0) => Math.Max(t.ac, t.bc),
        _ => -1
    };
}

还有一种可能性是使用具有嵌套属性模式的位置模式。位置模式之所以有效,是因为记录会自动生成一个Deconstructor。记录的析构函数以与在主构造函数中定义的顺序相同的顺序呈现元素。记录

record Thing(List<int> a, List<int> b);
生成这个解构函数:

public void Deconstruct(out List<int> a, out List<int> b)
{
    a = this.a;
    b = this.b;
}

位置模式:

int DoStuff2(Thing thing)
{
    return thing switch {
        ( { Count: > 5 }, _) => thing.a.Count,
        (_, { Count: > 5 }) => thing.b.Count,
        _ when thing.a.Count + thing.b.Count > 5 => thing.a.Count + thing.b.Count,
        ( { Count: > 0 }, { Count: > 0 }) => Math.Max(thing.a.Count, thing.b.Count),
        _ => -1
    };
}

这种方法允许您打开任何属性,甚至可以打开多个属性。打开

thing
这些也是有效的模式:

  • ( { Count: > 5, Capacity: < 100 }, _)
  • { a.Count: > 5 }
  • { a.Count: > 0, b.Count: > 0 }

所以,有很多不同的方式来制定模式。

© www.soinside.com 2019 - 2024. All rights reserved.