C#中编译期可以检测到的类型转换失败
条评论严格来说,这算是 C# 基础知识的一部分。不知是太久远我记不清了,还是这部分本来就没注意,最近发现了,不算坑,在这里写一下。
描述
请看下面这段代码:
1 | var s = "s"; |
我们知道,不管是 String
,还是 Dictionary<TKey, TValue>
,都没实现 IDisposable
,所以这两个地方都是没法转换的。可是奇怪的是,编译时,disposable1
那一行会报 Error,而第二个转换则是运行时才会抛出异常。
我一开始以为是编译器特殊处理了一些内置类型,准备过会儿查查文档。
原因
然后我又去翻了 EF Core 和 System.Linq.Async 一起使用出现冲突的问题,找到了在 EF Core 6.0 中修复这个问题的 Pull Request。其中的讨论提醒了我。
上面说,虽然 DbSet<TEntity>
不再实现 IAsyncEnumerable<TEntity>
,但是它的具体类一定会实现,这就是可以转换的原因。
我猛地想起刚才那个现象,像 String
、Int32
这样的类型,要么是 sealed class
,要么是 struct
,都不可能有派生类了。这样,编译器完全可以在编译期就发现,这个转换没法进行,因为没有派生类可以再去实现接口了。
要验证也非常简单,手写下面代码。
1 | public class MyClass { } |
这段代码可以通过编译。然后把类加上 sealed
。
1 | public sealed class MyClass { } |
此时就无法通过编译了。
文档
在我查找的范围内,文档中对此现象的描述比较模糊,仅说显示转换可能失败,并在运行时抛出异常。