无法将委托强制转换为泛型类型 T

本文关键字:转换 泛型类型 | 更新日期: 2023-09-27 18:34:08

为什么我们不能将委托的实例转换为泛型类型T

考虑一个实用程序方法CreateDelegate,它创建一个 T 实例,它是一个委托,即从 MulticastDelegate 派生的类型。

 T CreateDelegate<T>() {… }

不幸的是,泛型不允许将T约束为派生的类型,MulticastDelegate给出以下编译错误:

约束不能是特殊类"系统.多播委托">

尽管如此,此实用程序方法正在检查T是否与MulticastDelegate兼容,并通过反射通过Delegate::CreateDelegate创建委托。但是,如果我们尝试将Delegate::CreateDelegate的结果转换为 T ,我们将得到以下编译错误:

无法将类型"系统.委托"转换为"T">

但是,如果我先将其转换为object,然后再投射到T它将正常工作:

T h = (T) ((object) Delegate.CreateDelegate(typeof(T), target, m));

为什么我们不能直接将委托投给 T?

无法将委托强制转换为泛型类型 T

C# 语言强制进行静态检查,从类型 X 到类型 Y 的强制转换是否有效,即编译器可以(在一定程度上(保证兼容性并拒绝编译时明确的错误是否有意义。不受约束的泛型类型TSystem.Delegate没有任何直接的共同点。然而,当强制转换为object时,编译器知道每个类型本质上都是一个object,所以它允许强制转换。这并不意味着运行时类型检查在特定情况下不会失败。

as运算符更宽松一些,因为它不会导致无效强制转换异常。编译器在应用静态检查方面也不太严格。在您的特定情况下,这很有帮助,因为您可以省略中间转换以object并使用as T。但是,需要as仅适用于类类型,因此您必须应用 where T : class 约束。

因此,该方法将如下所示(简化(:

public T CreateDelegate<T>(…) where T : class
{
    return Delegate.CreateDelegate(typeof(T), …) as T;
}

正如@usr建议的那样,推荐阅读的是 Eric Lippert 的博客,例如这篇关于强制转换和类型参数的文章。