web-dev-qa-db-fra.com

Contrainte générique pour faire correspondre les 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 construis. Fondamentalement, 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 fonctionne pas, car cela correspondra également à string et bool, et peut-être autre chose que j'oublie. puis-je faire quelque chose pour ne faire correspondre que les types numériques? (Plus précisément, les types qui implémentent le > et < opérateurs, pour que je puisse les comparer ... Si cela signifie que je fais également correspondre les dates, cela n'a pas vraiment d'importance - l'extension fera toujours ce que j'attends.)

77
Tomas Aschan

Dans ce cas, vous souhaitez contraindre votre générique à l'interface IComparable, ce qui vous donne accès à la méthode CompareTo, car 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 ne devrait pas vous déranger autant.

53
flq
where T : struct, 
          IComparable, 
          IComparable<T>, 
          IConvertible, 
          IEquatable<T>, 
          IFormattable

C'est le plus proche que je peux obtenir 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 sont un type de référence, elles ne sont donc pas applicables.

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

40
Mark H
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 struct si vous le souhaitez.

16
Lee

Il est difficile de se limiter aux seuls chiffres, car il n'y a rien de commun comme INumeric à utiliser comme filtre. En fait, je soupçonne que l'approche la plus simple ici consiste à pas 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 générique IComparable<T> et le non générique IComparable, et prend en charge les types de référence, les types de valeur et l'utilisation accrue via Nullable<T>.

Pour une utilisation complète de l'opérateur , regardez classe Operator de MiscUtil et GreaterThan etc, qui peut être utile si vous voulez vraiment utiliser l'opérateur (plutôt que l'interface). Il donne également accès aux autres opérateurs comme Add etc.

6
Marc Gravell

Stackoverflow est jonché de ce genre de question. Jetez un oeil à cette recherche . C # ne prend pas en charge un moyen de définir un type générique contraint par des nombres. Malheureusement, votre meilleur pari est d'implémenter la méthode d'extension sur tous les objets et de faire un changement basé sur le type ou de créer un ensemble de méthodes pour les entiers, les doubles, les flottants, etc.

4
Jake Pearson

Cette solution de contournement peut aider: Solution de contournement à l'aide de stratégies . Il offre une sécurité de temps de compilation.

0
Sergey Shandar