对泛型类型进行反类型转换

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

假设如下示例:处理数据库连接的通用方法。DbConnection.BeginTransaction()(来自System.Data.Common)返回一个DbTransaction实例。既然这是显式声明的,为什么我需要显式转换它呢?

internal abstract class ADatabase<DbCommandType, DbConnectionType, DbTransactionType> : IDisposable
    where DbCommandType : DbCommand, new()
    where DbConnectionType : DbConnection, new()
    where DbTransactionType : DbTransaction, new()
{
    DbConnectionType _connection;
    DbTransactionType _transaction;
    void Foo()
    {
        _transaction = _connection.BeginTransaction(); // <-- Error..
    }
}

得到的错误是

错误1无法隐式转换类型"System.Data.Common"。从"DbTransaction"到"DbTransactionType"。存在显式转换(您是否缺少强制类型转换?)

当然可以强制转换,但问题是为什么要?

对泛型类型进行反类型转换

你的泛型有一个约束,说DbTransactionType需要是类DbTransaction 或从它派生的任何类

有了这个高亮显示,应该很清楚,你甚至不应该显式地强制转换它。

但如果不清楚:BeginTransaction的返回值是DbTransaction类型的实例。_transaction的类型为DbTransactionType,可能是DbTransaction子类。不进行强制类型转换,就不能将基类的变量赋值给子类的变量。只有当基类的变量实际上包含该子类的实例时,强制类型转换才会起作用。

思考这个问题时,在你的心智模型中将DbTransactionType替换为string,将DbTransaction替换为object。现在问题应该马上就清楚了。

您只需将DbTransactionType限制为DbTransaction 或任何子类,只要该类型具有无参数构造函数。因此,虽然您可以使用任何子类来代替DbTransaction,但在另一个方向上并非如此,DbTransactionType可以引用这样的子类,从而使DbTransaction的分配有问题。