假设以下示例。数据库连接处理的通用方法。
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'。存在显式转换(您是否错过了演员?)
当然我可以施展它,但问题是为什么?
答案 0 :(得分:3)
您的通用语的约束条件是DbTransactionType
必须是类DbTransaction
或从中派生的任何类。
有了这个亮点,你应该清楚的是你甚至不应该明确地施展它。
但如果不清楚:
BeginTransaction
的返回值是类型DbTransaction
的实例。 _transaction
的类型为DbTransactionType
,可以是DbTransaction
的子类。您无法在不进行强制转换的情况下将基类的变量分配给子类的变量。只有当基类的变量实际包含该子类的实例时,强制转换才会起作用。
在考虑此问题时,在您的心智模型中,将DbTransactionType
替换为string
,将DbTransaction
替换为object
。现在问题应该立即变得明确。
答案 1 :(得分:3)
您只需将DbTransactionType
限制为DbTransaction
或任何子类,只要该类型具有无参数构造函数即可。因此,虽然您可以使用任何子类代替DbTransaction
,但在另一个方向上不是这样,DbTransactionType
可以引用这样的子类,从而使DbTransaction
的赋值成为问题。