2009-08-17 4 views
4

Je pense que ce serait plus clair avec cet exemple. Nous voulons voir deux méthodes avec des paramètres diferrent dans la classe de processeur. "int Process (valeur int);" "double processus (double valeur);" Mais le compilateur dit pour IRoot: 'Generics.IRoot' ne peut pas implémenter 'Generics.IProcess' et 'Generics.IProcess' car ils peuvent unifier pour certaines substitutions de paramètres de type.Comment utiliser deux fois la même interface avec des paramètres de modèle différents, dans une interface?

public class Processor : IRoot<int, double, int, double> 
{ 
    // Here we want 2 methods 
    public int Process(int item) { } 
    public double Process(double item) { } 
} 

public interface IProcess<TResult, TItem> 
{ 
    TResult Process(TItem item); 
} 

public interface IRoot<TR1, TR2, TItem1, TItem2> : 
    IProcess<TR1, TItem1>, 
    IProcess<TR2, TItem2> 
{ 

} 
+1

Quelle est la question? ce n'est absolument pas clair avec votre code ... Donnez quelques détails et explications, pas seulement un morceau de code! –

+0

La question est dans l'en-tête: "Comment utiliser la même interface deux fois avec des paramètres de modèle diferrent, dans une interface?" –

+0

Le problème est que la seule façon de savoir * pourquoi * vous ne pouvez pas faire ceci est de copier et coller le code dans un compilateur, et essayer de le compiler. Vous devriez publier le message d'erreur que vous obtenez du compilateur, ce qui permet aux utilisateurs de répondre plus facilement. Ne supposez jamais que les gens prendront la peine de sauter à travers beaucoup de cerceaux pour vous aider, nous aider à vous aider, nous fournir autant d'informations que possible. –

Répondre

-3

Vous pourriez probablement utiliser ce type d'implémentation. Vous allez perdre des arguments génériques:

public interface IBase<TM, TPkey> 
    where TM : bType 
    where TPkey : new()   
{ 
    TM Get(TPkey key); 
} 

public interface IABase<TPK> : IBase<ConcreteTmA, TPK> {} 
public interface IBBase<TPK> : IBase<ConcreteTmB, TPK> {} 

public class Root <TPK> : 
    IABase<TPK>, 
    IBBase<TPK> 
    where TM : MType 
    where TPM : PMType 
    where TPK : new() 
{ 
    ConcreteTmA IABase.Get(TPK key) 
    { 
    } 

    ConcreteTmB IBBase.Get(TPK key) 
    { 
    } 
} 
+0

Je ne comprends pas votre code ici, vous avez des interfaces sans {..} bloc, vous avez une interface qui a des implémentations de méthodes, vous avez plus de contraintes de paramètres génériques dans IRoot que de paramètres génériques, etc. le mot "probablement", et rendre le code capable de compiler au minimum. –

+0

Correction des accolades et je pense que tout le monde sait ce que je veux dire ... –

+0

Le "mot probablement" est parce que cette solution est seulement possible s'il y a un nombre limité de types possibles de TM et si IRoot sans tous les arguments génériques est acceptable. –

1

D'après ce que je comprends, vous voulez définir une interface comme celle-ci:

public interface IRoot<TM, TPM, TPK> 
    where TM : MType 
    where TPM : PMType 
    where TPK : new() 
{ 
    TM Get(TPK key); 
    TPM Get(TPK key); 
} 

Et ce n'est pas possible, parce que vous ne pouvez pas définir deux méthodes avec le même nom et le même paramètres. Essayez de définir votre interface directement (sans héritage) et changez les noms des méthodes. Par exemple:

public interface IRoot<TM, TPM, TPK> 
    where TM : MType 
    where TPM : PMType 
    where TPK : new() 
{ 
    TM GetTM(TPK key); 
    TPM GetTPM(TPK key); 
} 
2

Le problème est exactement ce que le message d'erreur dit:

'IRoot<TM,TPM,TPK>' cannot implement both 'IBase<TM,TPK>' and 
'IBase<TPM,TPK>' because they may unify for some type parameter substitutions 

Par exemple, vous pouvez le faire:

public class Test : IRoot<Int32, Int32, Int32> 

auquel cas il aurait deux successions chaînes à IBase<Int32, Int32> ce qui n'est pas autorisé.

Comme toujours, essayez d'inclure le problème que vous rencontrez ainsi que le code avec le problème.

1

Désolé de vous voir avoir tant de downvotes sur ce sujet, je suis confronté au même problème.

Malheureusement, il ne semble pas être possible - cette page MSDN répertorie les seules contraintes de type générique possibles, et nul ne peut exprimer la contrainte « T et U peut être tout type, mais doit avoir des hiérarchies d'héritage distincts » http://msdn.microsoft.com/en-us/library/d5x73970(v=vs.80).aspx

Nous avons vraiment besoin d'une sorte de syntaxe where T !: U ou where T, U disjoint; mais en l'état, il n'y a aucun moyen de spécifier au compilateur que les instances TItem1 et TItem2 ne peuvent jamais être substituables l'une à l'autre.

+0

Oui, moi aussi. Venant de l'espace extérieur de toutes les choses possibles, vous auriez besoin de capacités linguistiques spéciales pour nommer ou identifier les bases individuelles sur lesquelles vous pourriez lancer l'objet, afin qu'elles puissent être séparées, même lorsqu'elles sont unifiées. –

+0

Voir ma solution ci-dessous ... –

2

Voici ma solution. C'est basé sur l'utilisation de la différenciation afin que vous puissiez être clair sur l'interface que vous voulez. Vous devez ajouter un paramètre non utilisé, mais c'est ce qui indique ce que vous voulez.

public interface First { } 
public interface Second { } 

public class Processor : IRoot<int, double, int, double> 
{ 
    // Here we want 2 methods 
    public int Process (int item) { System.Console.WriteLine ("int Process"); return item + 1; } 
    public double Process (double item) { System.Console.WriteLine ("double Process"); return item + 10.748; } 
} 

public class TestProcessor : IRoot<int, int, int, int> 
{ 
    int IProcessWithDifferentiator<int, int, First>.Process (int item) 
    { 
     System.Console.WriteLine ("int Process"); return item + 1; 
    } 
    int IProcessWithDifferentiator<int, int, Second>.Process (int item) 
    { 
     System.Console.WriteLine ("int Process"); return item + 100302; 
    } 
} 

public interface IProcessWithDifferentiator<TResult, TItem, TDiff> 
{ 
    TResult Process (TItem item); 
} 

public interface IRoot<TR1, TR2, TItem1, TItem2> : 
    IProcessWithDifferentiator<TR1, TItem1, First>, 
    IProcessWithDifferentiator<TR2, TItem2, Second> 
{ 

} 

class Program 
{ 
    static void Main (string [] args) 
    { 
     Processor p = new Processor(); 
     IProcessWithDifferentiator<int, int, First> one = p; 
     System.Console.WriteLine ("one.Process(4) = " + one.Process (4)); 
     IProcessWithDifferentiator<double, double, Second> two = p; 
     System.Console.WriteLine ("two.Process(5.5) = " + two.Process (5.5)); 

     TestProcessor q = new TestProcessor(); 
     IProcessWithDifferentiator<int, int, First> q1 = q; 
     System.Console.WriteLine ("q1.Process(4) = " + q1.Process (4)); 
     IProcessWithDifferentiator<int, int, Second> q2 = q; 
     System.Console.WriteLine ("q2.Process(5) = " + q2.Process (5)); 

     System.Console.ReadLine(); 
    } 
} 

Voici la sortie.comme vous pouvez le voir ci-dessus

int Process 
one.Process(4) = 5 
double Process 
two.Process(5.5) = 16.248 
int Process 
q1.Process(4) = 5 
int Process 
q2.Process(5) = 100307 

Cela fonctionnera même si vous utilisez IRoot<int,int,int,int>; il sait (parce que nous le disons) quel IDifferentiatedProcess utiliser.

(Dans le cas où il importe, je suis sur Visual Studio 2012.)

+0

solution imaginative, ressemble à la meilleure que nous allons être en mesure de faire avec C# –

+0

Je suis toujours à la recherche d'un moyen de supprimer plus tard le paramètre différent ... –

+0

J'ai posté une deuxième réponse qui adresse la suppression du paramètre de différenciation, mais malheureusement c'est un peu moche, en utilisant un proxy. –

3

Donc, après avoir publié ma première réponse à cette question (#1), je compris alors que l'on pourrait souvent veulent être en mesure de convertir une valeur de une interface différenciée à une interface non différenciée. En d'autres termes, on veut faire le

suivant
IProcessWithDifferentiator<TRes, TItem, TDiff> : IProcess<TRes, TItem> 

mais nous ne pouvons pas parce que nous allons courir dans la même erreur (types pourraient unifier) ​​lors de l'utilisation de l'interface.

Je remarque que le PO ne l'a pas spécifiquement demandé, mais on peut voir que ce serait le prochain scénario logique. Donc, revenons à la table à dessin, et revenons avec une solution laide pour cela, qui est celle d'avoir une méthode retournant le type converti en bas, et un proxy pour supporter la construction de telles méthodes. (La seule atténuation de la laideur est que la classe de remplacement peut être quelque peu réutilisée comme indiqué ci-dessous.) Voici le résultat de cet exercice.

public interface Second { } 
public interface Third { } 

public class Processor : IRoot<float, int, double, float, int, double> 
{ 
    // Here we want 3 methods 
    public float Process (float item) { System.Console.WriteLine (" ...float Process..."); return (float) (item - 55.75); } 
    public int Process (int item) { System.Console.WriteLine (" ...int Process..."); return item + 1; } 
    public double Process (double item) { System.Console.WriteLine (" ...double Process..."); return item + 10.748; } 

    IProcess<int, int> IProcessWithDifferentiator<int, int, Second>.ConvertToBase() 
    { 
     return new TP_Proxy<int, int, Second> (this); 
    } 

    IProcess<double, double> IProcessWithDifferentiator<double, double, Third>.ConvertToBase() 
    { 
     return new TP_Proxy<double, double, Third> (this); 
    } 
} 

public class TestProcessor : IRoot<int, int, int, int, int, int> 
{ 
    int IProcess<int, int>.Process (int item) 
    { 
     System.Console.WriteLine (" ...int Process1..."); return item - 11; 
    } 
    int IProcessWithDifferentiator<int, int, Second>.Process (int item) 
    { 
     System.Console.WriteLine (" ...int Process2..."); return item + 12; 
    } 
    int IProcessWithDifferentiator<int, int, Third>.Process (int item) 
    { 
     System.Console.WriteLine (" ...int Process3..."); return item + 100302; 
    } 

    IProcess<int, int> IProcessWithDifferentiator<int, int, Second>.ConvertToBase() 
    { 
     return new TP_Proxy<int, int, Second> (this); 
    } 

    IProcess<int, int> IProcessWithDifferentiator<int, int, Third>.ConvertToBase() 
    { 
     return new TP_Proxy<int, int, Third> (this); 
    } 
} 

public interface IProcess<TResult, TItem> 
{ 
    TResult Process (TItem item); 
} 

public interface IProcessWithDifferentiator<TResult, TItem, TDiff> // would love to ": IProcess<TResult, TItem>" here but won't work above 
{ 
    TResult Process (TItem item); // replicated method from IProcess... yuck(!) 
    IProcess<TResult, TItem> ConvertToBase(); 
} 

// Having a proxy sucks. But at least this proxy is shared among multiple classes implementing the IProcess concept. 
class TP_Proxy<TResult, TItem, TDiff> : IProcess<TResult, TItem> 
{ 
    public TP_Proxy (IProcessWithDifferentiator<TResult, TItem, TDiff> px) { _proxyTo = px; } 
    private IProcessWithDifferentiator<TResult, TItem, TDiff> _proxyTo; 
    TResult IProcess<TResult, TItem>.Process (TItem item) { return _proxyTo.Process (item); } 
} 

public interface IRoot<TR1, TR2, TR3, TItem1, TItem2, TItem3> : 
    IProcess<TR1, TItem1>, 
    IProcessWithDifferentiator<TR2, TItem2, Second>, 
    IProcessWithDifferentiator<TR3, TItem3, Third> 
{ 
} 

class Program 
{ 
    static void Main (string [] args) 
    { 
     Processor p = new Processor(); 
     // Direct conversion of first one, of course 
     IProcess<float, float> a1 = p; 
     System.Console.WriteLine ("a1 .Process(3.3) = " + a1.Process ((float) 3.3)); 

     // Conversion of differentiated class 
     IProcessWithDifferentiator<int, int, Second> a2 = ((IProcessWithDifferentiator<int, int, Second>) p); 
     System.Console.WriteLine ("a2d.Process(4)  = " + a2.Process (4)); 
     IProcessWithDifferentiator<double, double, Third> a3 = (IProcessWithDifferentiator<double, double, Third>) p; 
     System.Console.WriteLine ("a3d.Process(5.5) = " + a3.Process (5.5)); 

     // Conversions to undifferentiated class using ugly proxies 
     IProcess<int, int> a2u = ((IProcessWithDifferentiator<int, int, Second>) p).ConvertToBase(); 
     System.Console.WriteLine ("a2u.Process(4)  = " + a2u.Process (4)); 
     IProcess<double, double> a3u = ((IProcessWithDifferentiator<double, double, Third>) p).ConvertToBase(); 
     System.Console.WriteLine ("a3u.Process(5.5) = " + a3u.Process (5.5)); 

     TestProcessor q = new TestProcessor(); 

     IProcess<int, int> b1 = q; 
     // Direct conversion of first one, of course 
     System.Console.WriteLine ("b1 .Process(3)  = " + b1.Process (3)); 

     // Conversion of differentiated class 
     IProcessWithDifferentiator<int, int, Second> b2d = (IProcessWithDifferentiator<int, int, Second>) q; 
     System.Console.WriteLine ("b2d.Process(4)  = " + b2d.Process (4)); 
     IProcessWithDifferentiator<int, int, Third> b3d = (IProcessWithDifferentiator<int, int, Third>) q; 
     System.Console.WriteLine ("b3d.Process(5)  = " + b3d.Process (5)); 

     // Conversions to undifferentiated class using ugly proxies 
     IProcess<int, int> b2u = ((IProcessWithDifferentiator<int, int, Second>) q).ConvertToBase(); 
     System.Console.WriteLine ("b2u.Process(4)  = " + b2u.Process (4)); 
     IProcess<int, int> b3u = ((IProcessWithDifferentiator<int, int, Third>) q).ConvertToBase(); 
     System.Console.WriteLine ("b3u.Process(5)  = " + b3u.Process (5)); 

     System.Console.ReadLine(); 
    } 
} 

La sortie est la suivante:

...float Process... 
a1 .Process(3.3) = -52.45 
    ...int Process... 
a2d.Process(4)  = 5 
    ...double Process... 
a3d.Process(5.5) = 16.248 
    ...int Process... 
a2u.Process(4)  = 5 
    ...double Process... 
a3u.Process(5.5) = 16.248 
    ...int Process1... 
b1 .Process(3)  = -8 
    ...int Process2... 
b2d.Process(4)  = 16 
    ...int Process3... 
b3d.Process(5)  = 100307 
    ...int Process2... 
b2u.Process(4)  = 16 
    ...int Process3... 
b3u.Process(5)  = 100307 
Questions connexes