9
votes

Est-il possible de contraindre un paramètre de type de méthode générique C # générique comme "assignable de" le paramètre de type de classe contenant "?

Je soupçonne que la réponse est non, mais je veux savoir s'il est possible de faire quelque chose comme ceci: xxx

ce que je veux indiquer dans l'exemple ci-dessus (non fonctionnel) est de contraindre tsomeinterface de telle sorte qu'il peut s'agir d'une classe de base, d'une interface mise en œuvre ou (si vous voulez vraiment avoir envie de gêner) une conversion implicite de myGenericClass .

Note: Je soupçonne que la raison pour laquelle cela n'a jamais été mis en œuvre dans C # est que les contraintes génériques ne sont pas vraiment destinées à être des contrats de code, ce que j'essaie de les utiliser ici. Je ne me soucie vraiment pas de quel type tsomeinterface est, tant qu'il est implémenté par Tsomeclass .

Jusqu'ici, j'ai piraté cela ensemble: xxx

ceci plus ou moins applique la contrainte que je veux (que Tsomeclass doit hériter de, ou dans le cas d'une interface, de mettre en œuvre, < Code> TsomeInterface ), mais l'appelant est très maladroit, car je dois spécifier TintermediateType Tsomeclass ): < / p> xxx

En outre, le hack ci-dessus est brisé car un appelant pourrait en théorie Spécifier une sous-classe de Tsomeclass comme premier paramètre de type, où seul la sous-classe implémente tsomeinterface .

La raison pour laquelle je veux faire cela est que j'écris un modèle d'usine fluide pour un service WCF et je les comme pour empêcher l'appelant (au moment de la compilation) d'essayer de créer un point de terminaison avec un contrat que le La classe de service ne met pas en œuvre. Je peux évidemment vérifier cela au moment de l'exécution (WCF en fait cela pour moi), mais je suis un grand fan de vérification du temps compilé.

Y a-t-il un moyen meilleur / plus élégant d'atteindre ce que je suis après ici?


10 commentaires

Ceci est pratiquement impossible puisque vous essayez de mélanger des génériques avec le temps d'exécution.


Non, je ne suis pas. Je viens d'essayer d'appliquer une contrainte générique qui (autant que je puisse dire) la langue C # ne permet pas (contraignant un paramètre de type de type, il s'agit d'une superclasse ou d'une interface mise en œuvre d'un paramètre de type dans la classe contenant).


Pour autant que je sache, vous essayez de contraindre la classe générique basée sur les données de type que vous utilisez à une méthode. Si vous souhaitez contraindre votre classe générique, vous devez le faire sur un niveau de classe (logiquement), il n'existe aucun moyen pour le compilateur JIT de créer une classe concrète.


J'essaie de contraindre le paramètre de la méthode, mais je le fais en arrière de l'ordre normal. Plutôt que TsomeInterface hériter de ou implémenter Tsomeclass , je veux qu'il soit contraint de l'ensemble des classes de base et des interfaces implémentées de Tsomeclass .


Ahh je vois maintenant, désolé pour le problème :)


@RJlohan, veuillez indiquer votre réponse, je pense que vous pouvez être sur la bonne voie!


J'assume une interface mobile jusqu'à la classe myGenericClass ne fonctionne pas pour votre cas? (serait un trival de mettre la restriction ...)


@Alexeilevenkov Il fait et, en réalité, c'est presque certainement la façon dont je vais résoudre cela dans mon code de code. À ce stade, c'est vraiment plus une question académique pour moi.


@Alexeilevenkov qui dit, il y a des cas de monde réel où cela ne le résoudrait pas. Imaginez que si vous vouliez appeler n méthodes sur myGenericClass, où n est arbitrairement> 1, et pour chacun de vous souhaiter fournir une interface différente.


Je vois. Je ne peux penser à rien de bacause Il n'y a pas de relation entre Tsomeclass et Tsomeinterface, il n'y aurait donc pas de moyen de convaincre le compilateur autrement. J'essaye d'essayer quelque chose de classe supplémentaire à appeler la méthode comme CLASS MODYCALLER : Où T: TI et l'instanciation avec MethodCaller Mais le compilateur serait ne pas être capable de comprendre si ça va :(.


3 Réponses :


3
votes

La façon dont j'ai pu envelopper ma tête autour de la raison pour laquelle cela ne compile pas est le suivant:

considère que ce programme compile: p> xxx pré>

tout est bon. Le compilateur est heureux. On considère maintenant que je change la méthode code> principale p>

static void Main(string[] args) {
    var inst = new MyGenericClass<Class1>();
    inst.MyGenericMethod<Class2>();
}


1 commentaires

Dans mon monde idéal, ce serait l'appel de la méthode bien sûr, comme si vous essayez de le faire: var x = nouvelle liste (); S.Ajouter (5); . Le compilateur suppose que la déclaration est correcte et que l'appel de la méthode utilise un argument invalide. +1 pour penser à la syntaxe cependant.



3
votes

Comme indiqué dans Cette question liée , Vous ne pouvez pas utiliser de paramètre de type qui ne se situe pas de la déclaration actuelle, à gauche d'un où code> clause.

ainsi comme suggéré par W0LF dans cette autre question, ce que vous pouvez faire Fournit les deux types de votre interface (plutôt que la méthode) DÉCLARATION: P>

public class MyGenericClass<TSomeClass> {
    public static void MyGenericMethod<TSomeClass, TSomeInterface>
                                         (MyGenericClass<TSomeClass> that) 
        where TSomeClass : TSomeInterface 
    {
        // use "that" instead of this
    }
}


0 commentaires

2
votes

Une méthode d'extension fournit la meilleure solution, bien qu'elle ne résolvait pas totalement toutes vos préoccupations.

var myGenericInstance = new MyGenericClass<TSomeClass>();
myGenericInstance.MyGenericMethod<TSomeClass, TSomeInterface>();


0 commentaires