C# 模式匹配与基类和泛型类型

问题描述

我有一段代码,用于检查对象是否属于 Sequence<T> 类型,该代码适用于 Task 类型的对象。

public class Sequence<T> {}

public class Task : Sequence<Task> {}

public class Program
{
    public static void Main()
    {
        var task = new Task();
                
        // These two are equivalent
        Console.WriteLine(IsSequence(task));
        Console.WriteLine(task is Sequence<Task>); 
    }
    
    public static bool IsSequence<TEntity>(TEntity entity)
    {
        return entity is Sequence<TEntity>;
    }
}

但是,现在我有一个新要求,这些其他类型 ToolAssembly 也应该匹配,而且我对 C# 中的模式匹配很陌生,所以不确定如何实现它.

public class Sequence<T> {}

public abstract class Item : Sequence<Item> {}

public class Task : Sequence<Task> {}

public class Tool : Item {}

public class Assembly : Item {}

public class Program
{
    public static void Main()
    {
        var ta = new Tool();
        var tt = new Assembly();
        var task = new Task();
                
        Console.WriteLine(IsSequence(ta));
        Console.WriteLine(IsSequence(tt));
        Console.WriteLine(IsSequence(task));
        
        // What I am posting here is an oversimplification of the real scenario
        // This code for checking if something is a Sequence or not is 
        // handled by a core class with shared functionality that can't kNow or use the 
        // proper typed overload required.
        // 
        // So doing this is not an option:
        //
        // Console.WriteLine(IsSequence<Item>(ta));
        
        // This is how the output should be
        Console.WriteLine(ta is Sequence<Item>);
        Console.WriteLine(tt is Sequence<Item>);
        Console.WriteLine(task is Sequence<Task>);
    }
    
    public static bool IsSequence<TEntity>(TEntity entity)
    {
        // How to rewrite (if possible) this pattern matching so that Task,Tool and Assembly match?
        // So basically I want to kNow if either TEntity or some of the base types is Sequence<base>
        return entity is Sequence<TEntity>;
    }
}

我知道它目前的编写方式不会匹配,因为 Tool/Assembly 不是 Sequence<Tool>/Sequence<Assembly>,所以我需要一种方法重写模式匹配以检查它是否为 Sequence<Item>

这是一个带有此示例的 C# Online Fiddle

解决方法

您编写函数的方式不起作用,因为 Tool 不是 Sequence<Tool>,而是 Sequence<Item>

如果您选择保留函数,无论出于何种原因,有很多方法可以编写它,但我会给您两种方法。

首先,您可以编写它来接收一个 object 参数,然后在里面使用 is Sequence<T> 来确定它是否是一个序列。这样做的问题是每次都需要提供类型参数,这里没有推论。

其次,你可以这样写:

    public static bool IsSequence<TEntity>(Sequence<TEntity> entity) => true;
    public static bool IsSequence(object obj) => false;

在这种情况下,不需要提供类型参数,只需使用您的对象调用它,它就会返回正确的值。由于它依赖于编译时重载解析,因此在运行时非常高效。此外,任何 C++ 程序员都应该熟悉它!

作为第三种选择,从您的 ISequence 类中提取一个接口 Sequence<T>,然后简单地使用 is ISequence 进行测试,没有类型参数,因为您似乎并不关心它测试。