2010-02-23 5 views
6

Je crée une classe générique personnalisée:C# Types génériques Causes Ambiguïté

class Widget< T1, T2> 
{ 
    ... 
    public bool Bar(T1 type1) 
    { 
     ... 
    } 
    public bool Bar(T2 type2) 
    { 
     ... 
    } 
    ... 
} 

Les lignes qui suivent, bien sûr, crée une erreur de compilation d'appel ambigu:

Widget<int, int> Foo = new Widget<int, int>(); 
... 
Foo.Bar(5); 
... 

Est-il possible autour de cette ? Y at-il une clause que je peux mettre sur les lignes de "où: TypeOf (T1)! = TypeOf (T2)", ou de toute façon de rendre cela sans ambiguïté? De préférence int, int serait disponible, mais ce n'est pas obligatoire.

Mise à jour:

En fait, je moi-même découvert une solution acceptable (pour moi) à ce problème, pour ceux qui sont intéressés

class Widget< T1, T2> 
{ 
    ... 
    public bool Bar(object o) 
    { 
     if(o.GetType() == typeof(T1)) 
     { 
      ... 
     } 
     if(o.GetType() == typeof(T2)) 
     { 
      ... 
     } 
    } 
    ... 
} 
+0

Je me demande quel est le cas du monde réel pour cela ... – user76035

+0

en réalité, il devient et la méthode invalide sur le chargement – Perpetualcoder

+1

@wwosik: Un dictionnaire avec 2 clés. –

Répondre

18

Is there a clause that I can put along the lines of "where : TypeOf(T1) != TypeOf(T2)"

Vous pourriez faire en sorte que votre constructeur lance une exception lors de l'exécution. Mais il n'y a aucun moyen d'empêcher cette situation à l'heure de compilation.

Any way to make this unambiguous?

Vous devez modifier les noms de vos méthodes afin qu'elles ne se chevauchent pas. C'est de loin la chose la plus sûre et la plus facile à faire. En fait, IIRC le CLR se réserve le droit de ne pas créer un type qui produit une ambiguïté dans les signatures de méthodes comme celle-ci. (Évidemment, notre mise en œuvre réussit réellement, mais vous marchez sur une glace très mince lorsque vous tirez ces sortes de manigances.)

Faire ce genre de chose est vraiment une très mauvaise idée parce que cela peut vous mener dans toutes sortes de situations. difficulté. Voici un exemple de la façon dont les choses vont terriblement mal:

http://blogs.msdn.com/ericlippert/archive/2006/04/05/odious-ambiguous-overloads-part-one.aspx

http://blogs.msdn.com/ericlippert/archive/2006/04/06/odious-ambiguous-overloads-part-two.aspx

Notez également que le compilateur va vous empêcher de créer un type tel qu'il implémente deux interfaces qui pourraient être identiques En construction. Cette pratique est illégale:

class C<T, U> : IFoo<T>, IFoo<U> { ... } 

parce que vous pouvez ensuite construire C<int, int> et le CLR n'aurait aucun moyen de savoir quelles méthodes qui correspondent aux emplacements d'interface.

Mais je semble avoir digressé un peu. Retour sur le sujet

Puisque vous êtes le créateur de cette classe, vous pouvez choisir de renommer vos méthodes "Bar" afin qu'elles soient différentes dans n'importe quelle construction possible. Supposons que vous choisissiez obstinément de ne pas le faire. Y at-il quelque chose que l'utilisateur de votre classe malheureuse peut faire si elles veulent faire Widget<int, int>? Oui, en fait, il y a, comme le souligne kvb. Ils peuvent définir des méthodes d'extension qui font la bonne chose.

public static void BarTheFirst<A, B>(this Widget<A, B> w, A a) 
{ 
    w.Bar(a); 
} 

public static void BarTheFirst<A, B>(this Widget<A, B> w, B b) 
{ 
    w.Bar(b); 
} 

résolution de surcharge se fait au moment de la compilation, et au moment de la compilation tout ce que nous savons est que le premier appelle la barre qui prend un « A », et le second appelle la barre qui prend " B ". Nous ne refaisons pas la résolution de surcharge à l'exécution, alors maintenant vous pouvez dire

Widget<int, int> w = whatever; 
w.BarTheFirst(5); 
w.BarTheSecond(10); 

et il fera le bon choix.

+0

"En fait, IIRC le CLR se réserve le droit de ne pas créer un type qui produit une ambiguïté dans les signatures de méthodes comme ça." Sérieusement? Si c'est le cas, le compilateur C# ne devrait-il pas cracher un avertissement (au moins) quand vous créez le 'Widget '? –

+0

Eh bien, c'est le cas: voir OP: "erreur de compilation d'appel ambigu" – user76035

+0

@wwosik: Cette erreur est pour l'appel de la méthode. Eric parle de CLR qui fait exploser le programme au moment où un tel type est ** créé **. En fait, quand j'y pense, il n'est pas facile pour le compilateur de comprendre que lorsqu'il est profondément imbriqué dans des méthodes génériques, disons des assemblages externes. –

5

Donnez à vos fonctions noms uniques

0

Cela ressemble à un cas où vous voulez une classe générique de base

abstract class WidgetBase<T1> 
{ 

    public abstract bool Bar(T1 type); 
    ... 
} 

héritera ensuite pour votre mise en œuvre

class WidgetA : WidgetBase<int> 
{ 
    public bool Bar(int type) 
    { 
     ... 
    } 
} 

class WidgetB : WidgetBase<int> 
{ 
    public bool Bar(int type) 
    { 
     ... 
    } 
} 
1

Je suis d'accord avec les autres que vous devriez changer votre classe afin que la collision ne se produit pas (par exemple en renommant les méthodes). Toutefois, si vous ne possédez pas la classe, il est une solution de contournement:

public static class WidgetExtensions 
{ 
    public static bool Bar1<T1,T2>(this Widget<T1, T2> w, T1 t1) { return w.Bar(t1); } 
    public static bool Bar2<T1,T2>(this Widget<T1, T2> w, T2 t2) { return w.Bar(t2); } 
} 

Vous pouvez utiliser ces méthodes d'extension pour appeler la surcharge Bar appropriée. Les méthodes statiques n'ont pas besoin d'être des méthodes d'extension, mais je pense que cela les rend un peu plus claires.