88 votes

Contrainte générique pour correspondre aux types numériques

J'essaie d'écrire une méthode d'extension sur les types numériques à utiliser dans un cadre de test fluide que je suis en train de construire. En gros, je veux faire ceci :

public static ShouldBeGreaterThan<T>(this T actual, T expected, string message)
    where T : int || T: double || etc...

Juste where T : struct ne fait pas l'affaire, puisque cela correspond aussi à string y bool et peut-être quelque chose d'autre que j'oublie. Y a-t-il quelque chose que je puisse faire pour ne faire correspondre que les types numériques ? (Plus précisément, les types qui implémentent la fonction > y < opérateurs, pour que je puisse les comparer... Si cela signifie que je compare aussi les dates, cela n'a pas vraiment d'importance - l'extension fera toujours ce que j'attends).

6 votes

Jon Skeet et Mark Gravell ont mis en place des cours intéressants à cet effet : yoda.arachsys.com/csharp/genericoperators.html

12 votes

@Dan en fait c'est "Marc", mais je vous laisse tranquille - très peu de gens le font correctement ;p

4 votes

Ce lien est mort. utilisez ceci à la place jonskeet.uk/csharp/miscutil jonskeet.uk/csharp/genericoperators.html

63voto

flq Points 11937

Dans ce cas, vous voulez contraindre votre générique à l'élément IComparable qui vous donne accès à l'interface CompareTo puisque cette interface vous permet de répondre à la question ShouldBeGreaterThan .

Les types numériques implémenteront cette interface et le fait qu'elle fonctionne également sur les chaînes de caractères ne devrait pas vous gêner outre mesure.

1 votes

C'est une meilleure solution qu'une interface d'opérateur plus générale pour les types numériques, du moins pour ce problème.

1 votes

Existe-t-il un moyen de permettre l'utilisation de == y > etc. plutôt que .Equals() y .CompareTo ?

0 votes

Ces opérateurs sont implémentés en tant que méthodes statiques - c'est-à-dire qu'actuellement, C# n'a aucun moyen de contraindre les caractéristiques statiques d'un type,

54voto

Mark H Points 9127
where T : struct, 
          IComparable, 
          IComparable<T>, 
          IConvertible, 
          IEquatable<T>, 
          IFormattable

C'est ce qui se rapproche le plus d'une contrainte numérique. Tous les types numériques implémentent ces 5 interfaces, mais IFormattable n'est pas implémenté par bool, et les chaînes de caractères sont un type de référence, donc elles ne sont pas applicables.

Il y a d'autres choses qui les implémentent - DateTime par exemple, donc ce n'est pas vraiment nécessaire, mais cela empêche beaucoup d'instanciations que vous ne voulez pas.

4 votes

Malgré cela, je ne parviens pas à utiliser les opérations mathématiques courantes. Operator '==' cannot be applied to operands of type 'T' and 'float'

20voto

Lee Points 63849
public static bool IsGreaterThan<T>(this T actual, T comp) where T : IComparable<T>
{
    return actual.CompareTo(comp) > 0;
}

Vous pouvez également ajouter la contrainte de structure si vous le souhaitez.

9voto

Marc Gravell Points 482669

Il est difficile de se limiter au numérique, car il n'y a rien de commun comme INumeric à utiliser comme filtre. En fait, je pense que l'approche la plus simple ici est de no insister sur la contrainte, et utiliser Comparer<T>.Default.Compare à l'intérieur de la méthode.

Ce type intégré prend en charge à la fois le type générique IComparable<T> et le non générique IComparable et supporte les ref-types, les value-types et l'usage lifté par le biais de Nullable<T> .

Pour l'intégralité opérateur l'utilisation, regardez MiscUtil's Operator classe y GreaterThan etc., ce qui peut être utile si vous vraiment veulent utiliser l'opérateur (plutôt que l'interface). Il permet également d'accéder aux autres opérateurs comme Add etc.

0 votes

Marc Gravell a déclaré : "C'est dur de se limiter aux seuls chiffres" mais il est possible tant au moment de l'exécution que de la compilation. Veuillez consulter ma réponse à la question "Existe-t-il une contrainte qui limite ma méthode générique aux types numériques ? stackoverflow.com/questions/32664/

1 votes

@Erez ça marchera, mais c'est la mort pour le code critique de performance - beaucoup de boxe et de vérification de type. Quelque part dans la période C#7.2-C#8.0, nous sommes susceptibles de voir des ajouts aux génériques pour faire cela beaucoup plus efficacement.

0 votes

J'ai hâte que cela soit pris en charge par Microsoft.

5voto

Jake Pearson Points 9657

Stackoverflow est truffé de ce genre de questions. Jetez un coup d'œil à cette recherche . C# ne permet pas de définir un type générique contraint par des nombres. Malheureusement, votre meilleure chance est d'implémenter la méthode d'extension sur tous les objets et d'effectuer une commutation basée sur le type ou de créer un ensemble de méthodes pour les ints, les doubles, les flottants, etc.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X