2010-03-26 18 views
4

Contexte:

Supposons que j'ai la classe suivante:Pourquoi cette conversion de type implicite en C# échoue-t-elle?

class Wrapped<T> : IDisposable 
{ 
    public Wrapped(T obj) { /* ... */ } 

    public static implicit operator Wrapped<T>(T obj) 
    { 
     return new Wrapped<T>(obj); 
    } 

    public void Dispose() { /* ... */ } 
} 

Comme vous pouvez le voir, il fournit un opérateur de conversion de type implicite pour TWrapped<T>. En fin de compte, je voudrais être en mesure d'utiliser cette classe comme suit:

interface IX { /* ... */ } 

class X : IX { /* ... */ } 

... 

IX plainIX = new X(); 

using (Wrapped<IX> wrappedIX = plainIX) 
{ 
    /* ... */ 
} 

Problème:

Cependant, la conversion de type dans la clause using ci-dessus échoue. Bien que je puisse attribuer un new X() directement à wrappedIX, je ne suis pas autorisé à lui assigner quoi que ce soit de type IX. Le compilateur se plaindra avec l'erreur suivante:

Compiler error CS0266: Cannot implicitly convert type 'IX' to 'Wrapped<IX>'. An explicit onversion exists (are you missing a cast?)

Je ne comprends pas cela. Quel est le problème ici?

+0

compilable si remplacer "IX plainIX = new X();" avec "X plainIX = new X();" – Nagg

+0

@Nagg: En raison de ce que j'essaie de réaliser (à savoir, de concevoir une interface fluide au-dessus d'une * bibliothèque COM * existante), il est absolument essentiel de programmer contre les interfaces. Par conséquent, votre suggestion n'est pas une option viable, malheureusement. – stakx

Répondre

5

Je crois que c'est parce que IX est une interface. Le compilateur pense que peut-être une valeur de type IX pourrait déjà être dérivé de Wrapped<IX> (même si Wrapped<T> est scellé) donc il n'utilise pas la conversion.

Les détails sont assez compliqués, dans les sections 6.4.3 et 6.4.4 de la spécification C# 3.0. Fondamentalement parce que IX est une interface, il n'est pas "englobé par" tous les types, ce qui signifie qu'une étape ultérieure dans 6.4.4 échoue.

Je vous suggère de créer un type non générique Wrapped avec cette méthode:

public static Wrapped<T> Of<T>(T item) 
{ 
    return new Wrapped<T>(item); 
} 

Ensuite, vous pouvez simplement écrire:

using (Wrapped<IX> wrappedIX = Wrapped.Of(plainIX)) 

Fondamentalement, les conversions peuvent être un peu difficile pour diverses raisons - simples les méthodes sont généralement plus faciles à comprendre, IMO.

+0

Cela fonctionnera avec C# 4, quand 'T' est correctement décoré avec' out', ou ne fonctionne-t-il pas pour un casting implicite? – Dykam

+0

@Dykam: Vous supposez que 'T' * peut * être utilisé de façon covariante. Je ne suis pas sûr de ce que vous entendez par "ceci" - mais comme le type de "plainIX" est "IX" plutôt que "X", je ne crois pas que le code original fonctionnerait hors de la boîte. –

+0

Hmm, en effet. Ensuite, j'ai raté cette partie. Les conversions implicites deviennent rapidement désordonnées dans tous les cas. – Dykam