为何C#中int[]实例能通过IList<T>类型模式匹配检测?
根据微软C#模式匹配文档,类型测试模式可用于检测变量是否非空且实现指定接口(如System.Collections.Generic.IList<T>),声明模式不会匹配null值。但在如下代码中,调用泛型方法ListExample<T>传入new int[] { 1 }时,该实例却通过了IList<T>的类型检测:
ListExample(new List<int> { 1 }); // 输出:Sequence is IList<T> ListExample(null as IList<int>); // 输出:Sequence was null. ListExample(new int[] { 1 }); // 输出:Sequence is IList<T> ?? public static void ListExample<T>(IEnumerable<T> sequence) { if (sequence is IList<T> list) { Console.WriteLine("Sequence is IList<T>"); } else if (sequence is null) { Console.WriteLine("Sequence was null."); } else { Console.WriteLine("Sequence was other type of IEnumerable<T>"); } }
查阅is/as运算符文档可知,is运算符检查表达式的运行时类型是否与给定类型兼容,as运算符则在兼容时执行显式转换。请问这是否意味着类型检测仅取决于能否转换为目标类型,而非是否实现接口?为何int[]实例能通过IList<T>的类型模式匹配检测?
1. 类型检测的核心逻辑:基于运行时类型兼容性
is运算符和类型模式匹配的核心是运行时类型与目标类型的兼容性,而非仅仅看源代码中是否显式声明实现接口。兼容性的判定范围包括:
- 类型直接显式实现目标接口
- 类型继承自已实现目标接口的父类
- CLR提供的特殊隐式接口实现(比如数组的情况)
- 合法的引用转换、装箱转换等
也就是说,只要运行时存在从表达式类型到目标类型的有效转换,is检测就会返回true,不管这个兼容性是来自显式代码声明还是CLR的特殊处理。
2. int[]能匹配IList的原因:CLR对数组的特殊处理
在.NET的CLR中,一维数组T[]会被隐式地视为实现了IList<T>、ICollection<T>等泛型集合接口——虽然从C#源代码层面看不到数组类显式声明这些接口,但CLR在运行时为数组类型提供了这些接口的实现(包括对应的方法逻辑,比如Count、IndexOf等)。
当你调用ListExample(new int[] {1})时,泛型参数T会被推断为int,此时目标类型是IList<int>。由于int[]在运行时与IList<int>兼容,所以sequence is IList<int> list的检测结果为true,从而输出对应的提示。
内容的提问来源于stack exchange,提问作者Zze

