首页 > 解决方案 > 与基类和泛型类型匹配的 C# 模式

问题描述

我有这段代码可以检查对象的类型是否Sequence<T>符合 Type 对象的预期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/ Assemblyare not Sequence<Tool>/不会匹配Sequence<Assembly>,所以我需要一种方法来重写模式匹配以检查它是否是Sequence<Item>.

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

标签: c#pattern-matching

解决方案


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

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

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

其次,你可以这样写:

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

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

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


推荐阅读