En lisant ceci , j'ai appris qu'il était possible d'autoriser une méthode à accepter des paramètres de plusieurs types en en faisant une méthode générique. Dans l'exemple, le code suivant est utilisé avec une contrainte de type pour s'assurer que "U" est un IEnumerable<T>
.
public T DoSomething<U, T>(U arg) where U : IEnumerable<T>
{
return arg.First();
}
J'ai trouvé un peu plus de code qui permettait d'ajouter plusieurs contraintes de type, telles que:
public void test<T>(string a, T arg) where T: ParentClass, ChildClass
{
//do something
}
Cependant, ce code semble appliquer qui arg
doit être à la fois un type de ParentClass
et ChildClass
. Ce que je veux faire, c'est dire que arg pourrait être un type de ParentClass
ou ChildClass
de la manière suivante:
public void test<T>(string a, T arg) where T: string OR Exception
{
//do something
}
Votre aide est appréciée comme toujours!
c#
asp.net-mvc-3
types
Mansfield
la source
la source
where T : string
, tout commestring
une classe scellée . La seule chose utile que vous puissiez faire est de définir des surcharges pourstring
etT : Exception
, comme expliqué par @ Botz3000 dans sa réponse ci-dessous.arg
sont celles définies parobject
- alors pourquoi ne pas simplement supprimer les génériques de l'image et en faire le typearg
object
? Que gagnez-vous?Réponses:
Ce n'est pas possible. Vous pouvez cependant définir des surcharges pour des types spécifiques:
Si ceux-ci font partie d'une classe générique, ils seront préférés à la version générique de la méthode.
la source
or
relation rend les choses trop générales pour être utiles. Vous souhaitez avoir à faire une réflexion pour savoir ce qu'il faut faire et tout ça. (Beurk!).La réponse de Botz est correcte à 100%, voici une courte explication:
Lorsque vous écrivez une méthode (générique ou non) et déclarez les types des paramètres que la méthode prend, vous définissez un contrat:
Si vous essayez de lui donner plus d'un type à la fois (en ayant un ou) ou essayez de le faire renvoyer une valeur qui pourrait être plus d'un type, ce contrat devient flou:
Le problème est que lorsque vous entrez dans la méthode, vous ne savez pas s'ils vous ont donné un
IJumpRope
ou unPiFactory
. De plus, lorsque vous utilisez la méthode (en supposant que vous l'avez compilée par magie), vous ne savez pas vraiment si vous avez unFisher
ou unAbstractConcreteMixer
. Fondamentalement, cela rend le tout beaucoup plus déroutant.La solution à votre problème est l'une des deux possibilités:
Définissez plusieurs méthodes qui définissent chaque transformation, comportement ou autre. C'est la réponse de Botz. Dans le monde de la programmation, on parle de surcharge de la méthode.
Définissez une classe ou une interface de base qui sait comment faire tout ce dont vous avez besoin pour la méthode et une seule méthode prend juste ce type. Cela peut impliquer de regrouper un
string
etException
dans une petite classe pour définir comment vous prévoyez de les mapper à l'implémentation, mais tout est alors très clair et facile à lire. Je pourrais venir, dans quatre ans, lire votre code et comprendre facilement ce qui se passe.Ce que vous choisissez dépend de la complexité des choix 1 et 2 et de leur capacité d'extension.
Donc, pour votre situation spécifique, je vais imaginer que vous sortez simplement un message ou quelque chose de l'exception:
Maintenant, tout ce dont vous avez besoin, ce sont des méthodes qui transforment a
string
et anException
en IHasMessage. Très facile.la source
Si ChildClass signifie qu'il est dérivé de ParentClass, vous pouvez simplement écrire ce qui suit pour accepter à la fois ParentClass et ChildClass;
D'un autre côté, si vous souhaitez utiliser deux types différents sans relation d'héritage entre eux, vous devez considérer les types implémentant la même interface;
alors vous pouvez écrire votre fonction générique comme;
la source
Aussi vieille que cette question soit, je reçois toujours des votes positifs aléatoires sur mon explication ci-dessus. L'explication tient toujours parfaitement bien telle quelle, mais je vais répondre une deuxième fois avec un type qui m'a bien servi en tant que substitut aux types d'union (la réponse fortement typée à la question qui n'est pas directement prise en charge par C # tel quel ).
La classe ci - dessus représente un type qui peut être soit TP ou TA. Vous pouvez l'utiliser comme tel (les types renvoient à ma réponse d'origine):
Notes IMPORTANTES:
IsPrimary
abord.IsNeither
IsPrimary
ouIsAlternate
.Primary
etAlternate
Either
n'importe où où l'on est attendu. Si vous faites passer unEither
où unTA
ouTP
devrait, maisEither
contient le mauvais type de valeur que vous obtiendrez une erreur d'exécution.J'utilise généralement ceci où je veux qu'une méthode renvoie un résultat ou une erreur. Cela nettoie vraiment ce code de style. J'utilise aussi très occasionnellement ( rarement ) ceci en remplacement des surcharges de méthode. En réalité, c'est un très mauvais substitut à une telle surcharge.
la source