具有相同别名的 switch 语句中的多个 case

Multiple cases in switch statement with same alias

我想知道是否有意见如何组合我的 switch 的 2 个案例,它们几乎相同,但一个用于可空值,而第二个不是。

        switch (rangeA)
        {
            case Range<int> intRangeA:
            {
                if (rangeB is Range<int> intRangeB)
                {
                    return intRangeA.ValueFrom <= intRangeB.ValueTo && intRangeA.ValueTo >= intRangeB.ValueFrom;
                }

                return false;
            }

            case Range<int?> intRangeA:
            {
                if (rangeB is Range<int?> intRangeB)
                {
                    return intRangeA.ValueFrom <= intRangeB.ValueTo && intRangeA.ValueTo >= intRangeB.ValueFrom;
                }

                return false;
            }
        }

这取决于 rangeArangeB 的数据类型。

假设他们是 object,您可以这样做。如果您创建 Range<Something non-comparable> 然后在其上调用 ContainsInclusive,它将在运行时抛出异常。如果你愿意,你可以为此添加一个额外的检查,但是它变得有点混乱,因为 Nullable<T> 没有实现任何接口,所以你必须求助于反射。

public class Program
{
    public static void Main()
    {
        Foo(new Range<int>() { ValueFrom = 1, ValueTo = 10 }, new Range<int>() { ValueFrom = 0, ValueTo = 10 });
        Foo(new Range<int?>() { ValueFrom = 1, ValueTo = 10 }, new Range<int?>() { ValueFrom = 0, ValueTo = 10 });
    }
    
    private static bool Foo(object rangeA, object rangeB)
    {
        return (rangeA, rangeB) switch
        {
            (Range<int> a, Range<int> b) => b.ContainsInclusive(a),
            (Range<int?> a, Range<int?> b) => b.ContainsInclusive(a),
            _ => false,
        };
    }
}

public class Range<T> 
{
    public T ValueFrom { get; set; }
    public T ValueTo { get; set; }
    
    public bool ContainsInclusive(Range<T> other)
    {
        return Comparer<T>.Default.Compare(other.ValueFrom, this.ValueTo) <= 0 &&
            Comparer<T>.Default.Compare(other.ValueTo, this.ValueFrom) >= 0; 
    }
}

如果您不能以这种方式使用新的 switch 表达式,您可以这样做:

private static bool Foo(object rangeA, object rangeB)
{
    return TryContainsInclusive<int>(rangeA, rangeB) ||
        TryContainsInclusive<int?>(rangeA, rangeB);
}

private static bool TryContainsInclusive<T>(object a, object b)
{
    if (a is Range<T> rangeA && b is Range<T> rangeB)
    {
        return rangeB.ContainsInclusive(rangeA);
    }
    
    return false;
}

如果 rangeArangeB 可以是通用类型,您可以使用更简单的方法:

private static bool Foo<T>(Range<T> rangeA, Range<T> rangeB)
{
    return rangeB.ContainsInclusive(rangeA);
}

如果 rangeArangeB 可以是一些基础 Range 类型,那么你可以这样做。同样,如果 T 不可比较,这将在运行时抛出:

public class Program
{
    public static void Main()
    {
        Foo(new Range<int>() { ValueFrom = 1, ValueTo = 10 }, new Range<int>() { ValueFrom = 0, ValueTo = 10 }).Dump();
        Foo(new Range<int?>() { ValueFrom = 1, ValueTo = 10 }, new Range<int?>() { ValueFrom = 0, ValueTo = 10 }).Dump();
    }
    
    private static bool Foo(Range rangeA, Range rangeB)
    {
        return rangeB.ContainsInclusive(rangeA);
    }
}

public abstract class Range
{
    public abstract bool ContainsInclusive(Range other);
}

public class Range<T> : Range
{
    public T ValueFrom { get; set; }
    public T ValueTo { get; set; }
    
    public override bool ContainsInclusive(Range other)
    {
        if (other is Range<T> o)
        {
            return Comparer<T>.Default.Compare(o.ValueFrom, this.ValueTo) <= 0 &&
                Comparer<T>.Default.Compare(o.ValueTo, this.ValueFrom) >= 0;    
        }
        
        return false;
    }
}

您也可以通过非抽象基础 class Range 来解决问题。 Range<int>Range<int?> 都与此基数 class.

兼容
class Range
{
    public object ValueFrom { get; protected set; }
    public object ValueTo { get; protected set; }
}

class Range<T> : Range
{
    public new T ValueFrom
    {
        get {
            return (T)base.ValueFrom;
        }
        set {
            base.ValueFrom = value;
        }
    }

    public new T ValueTo
    {
        get {
            return (T)base.ValueTo;
        }
        set {
            base.ValueTo = value;
        }
    }
}

通用 class 的属性隐藏了基础 class 的属性。他们的 setter 受到保护。因此设置值仍然是类型安全的,因为它只能通过泛型 class.

来完成

然后我的解决方案包括测试 From 和 To 值的类型。这也适用于可空类型。如果 nullable 为 null,则 nullable is int i 产生 false,否则如果我们有 Range<int?>,它将把 nullable.Value 分配给 i

这也允许您将 Range<int>Range<int?> 进行比较。

Range rangeA = new Range<int> { ValueFrom = 5, ValueTo = 12 };
Range rangeB = new Range<int?> { ValueFrom = 10, ValueTo = 18 };

if (rangeA.ValueFrom is int aFrom && rangeA.ValueTo is int aTo &&
    rangeB.ValueFrom is int bFrom && rangeB.ValueTo is int bTo) {

    return aFrom <= bTo && aTo >= bFrom;
}
return false;

一个可能的改进是在通用变体中有一个强类型的支持变量:

private T _valueFrom;
public new T ValueFrom
{
    get {
        return _valueFrom;
    }
    set {
        base.ValueFrom = _valueFrom = value;
    }
}

至少返回一个值然后在处理通用范围时不涉及拆箱。