2013-06-03 3 views
2

Supposons l'exemple suivant. Une approche générique du traitement de la connexion à la base de données. DbConnection.BeginTransaction() (à partir de System.Data.Common) renvoie une instance DbTransaction. Puisque cela est explicitement indiqué, pourquoi dois-je le lancer explicitement?Rétablissement des types génériques

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.. 
    } 
} 

L'erreur que je reçois est

Erreur 1 Impossible de convertir implicitement le type 'System.Data.Common.DbTransaction' à 'DbTransactionType'. Une conversion explicite existe (vous manque un casting?)

Bien sûr, je peux le jeter, mais la question est pourquoi ?

Répondre

3

Votre générique a une contrainte qui dit que DbTransactionType doit être la classe DbTransactionou de toute classe dérivée de celle-ci.

Avec ce point culminant, il devrait être clair que vous ne devriez même pas le lancer explicitement.

Mais si ce n'est pas clair: La valeur de retour de BeginTransaction est une instance de type DbTransaction. Le type de _transaction est DbTransactionType, ce qui pourrait être un sous-classe de DbTransaction. Vous ne pouvez pas affecter une variable d'une classe de base à une variable d'une sous-classe sans conversion. Et la conversion ne fonctionnera que si la variable de la classe de base contient réellement une instance de cette sous-classe. Lorsque vous pensez à ce problème, dans votre modèle mental, remplacez DbTransactionType par string et DbTransaction par . Maintenant, le problème devrait devenir clair immédiatement.

+0

Mon point exactement. Alors pourquoi l'erreur? – Odys

+0

@odyodyodys: Veuillez relire ma réponse. C'est la même chose que si vous demandez pourquoi vous devez lancer un 'object' quand vous voulez l'assigner à' string'. –

+0

La classe 'public abstraite DbConnection.BeginTransaction()' renvoie un 'DbTransaction' et non un' object'. S'il vous plaît corrigez-moi si cela est faux. – Odys

3

vous restreignez juste DbTransactionType-DbTransactionou toute sous-classe tant que le type a un constructeur sans paramètre. Donc, bien que vous puissiez utiliser n'importe quelle sous-classe à la place de DbTransaction, il n'en va pas de même dans l'autre direction et DbTransactionType pourrait faire référence à une telle sous-classe, rendant l'attribution d'une DbTransaction problématique.