Existe-t-il un moyen de déterminer si un type .Net donné est ou non un nombre? Par exemple: System.UInt32/UInt16/Doublesont tous des nombres. Je veux éviter un long boîtier de commutation sur le Type.FullName.
@Xaero: Je ne doute pas que ce decimalsoit numérique. Ce n'est pas parce que ce n'est pas une primitive que ce n'est pas numérique. Votre code doit en tenir compte.
LukeH
2
Cela devrait être repensé pour les nouveaux types numériques dans .NET 4.0 qui n'ont pas de codes de type.
Jon Skeet
7
Comment pouvez-vous me refuser une réponse basée sur la technologie actuelle. Peut-être que dans .NET 62, int sera supprimé - allez-vous voter contre toutes les réponses avec int?
Philip Wallace
1
@DiskJunky Désolé, mon ami. C'était il y a presque trois ans et je ne me souviens pas de leur contenu.
kdbanman
93
N'utilisez pas d'interrupteur - utilisez simplement un ensemble:
EDIT: Un avantage de ceci par rapport à l'utilisation d'un code de type est que lorsque de nouveaux types numériques sont introduits dans .NET (par exemple BigInteger et Complex ), il est facile à ajuster - alors que ces types n'obtiendront pas de code de type.
J'aurais pensé que le compilateur ferait une conversion implicite de l'instruction switch en hashset.
Rolf Kristensen
6
@RolfKristensen: Eh bien, switchcela ne fonctionne tout simplement pas Type, donc vous ne pouvez pas. Vous pouvez TypeCodebien sûr allumer , mais c'est une autre question.
Je sais que je pourrais simplement ajouter les nullables lui-même à mon HashSet. Mais cette solution évite le risque d'oublier d'ajouter un Nullable spécifique à votre liste.
Un type Nullable est-il vraiment numérique? Null n'est pas un nombre, à ma connaissance.
IllidanS4 veut que Monica revienne
2
Cela dépend de ce que vous voulez réaliser. Dans mon cas, je devais également inclure les nullables. Mais je pourrais aussi penser à des situations où ce n'est pas un comportement souhaité.
Jürgen Steinblock
Bien! Traiter un nombre Nullable comme un nombre est très utile dans la validation d'entrée de l'interface utilisateur.
guogangj
1
@ IllidanS4 La vérification est sur Tapez pas la valeur. Dans la plupart des cas, les types numériques Nullable doivent être traités comme numériques. Bien sûr, si le contrôle était sur la valeur et que la valeur est nulle, alors oui, elle ne devrait pas être considérée comme numérique.
Remarque sur l'optimisation supprimée (voir les commentaires enzi)
Et si vous voulez vraiment l'optimiser (perte de lisibilité et de sécurité ...):
publicstaticboolIsNumericType(Type type){TypeCode typeCode =Type.GetTypeCode(type);//The TypeCode of numerical types are between SByte (5) and Decimal (15).return(int)typeCode >=5&&(int)typeCode <=15;}
Je sais que cette réponse est ancienne, mais je suis récemment tombé sur un tel commutateur: n'utilisez pas l'optimisation suggérée! J'ai regardé le code IL généré à partir d'un tel commutateur et j'ai noté que le compilateur applique déjà l'optimisation (dans IL 5 est soustrait du code de type, puis les valeurs de 0 à 10 sont considérées comme vraies). Par conséquent, le commutateur doit être utilisé car il est plus lisible, plus sûr et tout aussi rapide.
enzi
1
Si vous voulez réellement l'optimiser et que vous ne vous souciez pas de la lisibilité, le code optimal serait return unchecked((uint)Type.GetTypeCode(type) - 5u) <= 10u;donc de supprimer la branche introduite par &&.
AnorZaken
14
Fondamentalement, la solution de Skeet, mais vous pouvez la réutiliser avec les types Nullable comme suit:
Avec C # 7, cette méthode me donne de meilleures performances que d'activer le boîtier TypeCodeet HashSet<Type>:
publicstaticboolIsNumeric(thisobject o)=> o isbyte|| o issbyte|| o isushort|| o isuint|| o isulong|| o isshort|| o isint|| o islong|| o isfloat|| o isdouble|| o isdecimal;
Les tests sont les suivants:
publicstaticclassExtensions{publicstaticHashSet<Type>NumericTypes=newHashSet<Type>(){typeof(byte),typeof(sbyte),typeof(ushort),typeof(uint),typeof(ulong),typeof(short),typeof(int),typeof(long),typeof(decimal),typeof(double),typeof(float)};publicstaticboolIsNumeric1(thisobject o)=>NumericTypes.Contains(o.GetType());publicstaticboolIsNumeric2(thisobject o)=> o isbyte|| o issbyte|| o isushort|| o isuint|| o isulong|| o isshort|| o isint|| o islong|| o isdecimal|| o isdouble|| o isfloat;publicstaticboolIsNumeric3(thisobject o){switch(o){caseByte b:caseSByte sb:caseUInt16 u16:caseUInt32 u32:caseUInt64 u64:caseInt16 i16:caseInt32 i32:caseInt64 i64:caseDecimal m:caseDouble d:caseSingle f:returntrue;default:returnfalse;}}publicstaticboolIsNumeric4(thisobject o){switch(Type.GetTypeCode(o.GetType())){caseTypeCode.Byte:caseTypeCode.SByte:caseTypeCode.UInt16:caseTypeCode.UInt32:caseTypeCode.UInt64:caseTypeCode.Int16:caseTypeCode.Int32:caseTypeCode.Int64:caseTypeCode.Decimal:caseTypeCode.Double:caseTypeCode.Single:returntrue;default:returnfalse;}}}classProgram{staticvoidMain(string[] args){var count =100000000;//warm up callsfor(var i =0; i < count; i++){
i.IsNumeric1();}for(var i =0; i < count; i++){
i.IsNumeric2();}for(var i =0; i < count; i++){
i.IsNumeric3();}for(var i =0; i < count; i++){
i.IsNumeric4();}//Tests begin herevar sw =newStopwatch();
sw.Restart();for(var i =0; i < count; i++){
i.IsNumeric1();}
sw.Stop();Debug.WriteLine(sw.ElapsedMilliseconds);
sw.Restart();for(var i =0; i < count; i++){
i.IsNumeric2();}
sw.Stop();Debug.WriteLine(sw.ElapsedMilliseconds);
sw.Restart();for(var i =0; i < count; i++){
i.IsNumeric3();}
sw.Stop();Debug.WriteLine(sw.ElapsedMilliseconds);
sw.Restart();for(var i =0; i < count; i++){
i.IsNumeric4();}
sw.Stop();Debug.WriteLine(sw.ElapsedMilliseconds);}
Le fait est que de nombreux types différents en C # peuvent contenir des données numériques. À moins que vous ne sachiez à quoi vous attendre (Int, Double, etc.), vous devez utiliser l'instruction case "long".
Cela peut également fonctionner. Cependant, vous souhaiterez peut-être le suivre avec un Type.Parse pour le convertir comme vous le souhaitez par la suite.
Le changement est un peu lent, car chaque fois que les méthodes dans la pire des situations passeront par tous les types. Je pense que l'utilisation de Dictonary est plus agréable, dans cette situation, vous aurez O(1):
Essayez le package nuget TypeSupport pour C #. Il prend en charge la détection de tous les types numériques (parmi de nombreuses autres fonctionnalités):
var extendedType =typeof(int).GetExtendedType();Assert.IsTrue(extendedType.IsNumericType);
Je ne connaissais pas ce paquet. Semble être un sauveur de vie dans de nombreux cas pour éviter d'écrire notre propre code pour le type d'opérations demandées par l'OP. Merci !
AFract le
0
Malheureusement, ces types n'ont pas grand-chose en commun à part ce sont tous des types de valeur. Mais pour éviter un long cas de commutation, vous pouvez simplement définir une liste en lecture seule avec tous ces types et ensuite simplement vérifier si le type donné est dans la liste.
Cela retournera vrai pour tout utilisateur défini struct... Je ne pense pas que ce soit ce que vous voulez.
Dan Tao
1
Vous avez raison. Les types numériques intégrés sont également des structures. Alors mieux vaut aller avec la comparaison primitive alors.
MandoMando
0
EDIT: Eh bien, j'ai modifié le code ci-dessous pour être plus performant, puis j'ai exécuté les tests postés par @Hugo contre lui. Les vitesses sont à peu près équivalentes à celles de @ Hugo en utilisant le dernier élément de sa séquence (Decimal). Cependant, si vous utilisez le premier élément «octet», il prend le gâteau, mais l'ordre est clairement important en termes de performances. Bien que l'utilisation du code ci-dessous soit plus facile à écrire et plus cohérente en termes de coût, elle n'est cependant pas maintenable ou à l'épreuve du futur.
On dirait que le passage de Type.GetTypeCode () à Convert.GetTypeCode () a accéléré considérablement les performances, environ 25%, VS Enum.Parse () qui était 10 fois plus lent.
Je sais que ce post est vieux , mais IF en utilisant la méthode ENUM TypeCode, plus facile (et probablement le moins cher) serait quelque chose comme ceci:
publicstaticboolIsNumericType(thisobject o){var t =(byte)Convert.GetTypeCode(o);return t >4&& t <16;}
Étant donné la définition d'énumération suivante pour TypeCode:
Je ne l'ai pas testé à fond, mais pour les types numériques de base C #, cela semble le couvrir. Cependant, comme @JonSkeet l'a mentionné, cette énumération n'est pas mise à jour pour les types supplémentaires ajoutés à .NET ultérieurement.
Oups! J'ai mal lu la question! Personnellement, je roulerais avec Skeet .
hrm, ressemble à ce que vous voulez DoSomethingsur Typevos données. Ce que vous pourriez faire est ce qui suit
publicclassMyClass{privatereadonlyDictionary<Type,Func<SomeResult,object>> _map =newDictionary<Type,Func<SomeResult,object>>();publicMyClass(){
_map.Add(typeof(int), o =>returnSomeTypeSafeMethod((int)(o)));}publicSomeResultDoSomething<T>(T numericValue){Type valueType =typeof(T);if(!_map.Contains(valueType)){thrownewNotSupportedException(string.Format("Does not support Type [{0}].", valueType.Name));}SomeResult result = _map[valueType](numericValue);return result;}}
Réponses:
Essaye ça:Poussant un peu plus loin la solution de Guillaume :
Usage:
la source
decimal
type n'est pas numérique?decimal
soit numérique. Ce n'est pas parce que ce n'est pas une primitive que ce n'est pas numérique. Votre code doit en tenir compte.N'utilisez pas d'interrupteur - utilisez simplement un ensemble:
EDIT: Un avantage de ceci par rapport à l'utilisation d'un code de type est que lorsque de nouveaux types numériques sont introduits dans .NET (par exemple BigInteger et Complex ), il est facile à ajuster - alors que ces types n'obtiendront pas de code de type.
la source
switch
cela ne fonctionne tout simplement pasType
, donc vous ne pouvez pas. Vous pouvezTypeCode
bien sûr allumer , mais c'est une autre question.Aucune des solutions ne prend en compte Nullable.
J'ai un peu modifié la solution de Jon Skeet:
Je sais que je pourrais simplement ajouter les nullables lui-même à mon HashSet. Mais cette solution évite le risque d'oublier d'ajouter un Nullable spécifique à votre liste.
la source
Remarque sur l'optimisation supprimée (voir les commentaires enzi)
Et si vous voulez vraiment l'optimiser (perte de lisibilité et de sécurité ...):la source
return unchecked((uint)Type.GetTypeCode(type) - 5u) <= 10u;
donc de supprimer la branche introduite par&&
.Fondamentalement, la solution de Skeet, mais vous pouvez la réutiliser avec les types Nullable comme suit:
la source
Approche basée sur la proposition de Philip , améliorée avec la vérification de type interne de SFun28 pour les
Nullable
types:Pourquoi ça? J'ai dû vérifier si un donné
Type type
est un type numérique, et non si un arbitraireobject o
est numérique.la source
Avec C # 7, cette méthode me donne de meilleures performances que d'activer le boîtier
TypeCode
etHashSet<Type>
:Les tests sont les suivants:
la source
Vous pouvez utiliser Type.IsPrimitive , puis trier les types
Boolean
etChar
, quelque chose comme ceci:EDIT : Vous pouvez exclure les
IntPtr
etUIntPtr
types aussi bien, si vous ne les considérez pas comme numérique.la source
decimal
type n'est pas numérique?Extension de type avec prise en charge de type nul.
la source
Réponse courte: Non.
Réponse plus longue: Non.
Le fait est que de nombreux types différents en C # peuvent contenir des données numériques. À moins que vous ne sachiez à quoi vous attendre (Int, Double, etc.), vous devez utiliser l'instruction case "long".
la source
Cela peut également fonctionner. Cependant, vous souhaiterez peut-être le suivre avec un Type.Parse pour le convertir comme vous le souhaitez par la suite.
la source
L' utilisation de modification au pigeon d' argile et la solution de arviman
Generics
,Reflection
etC# v6.0
.Suivi par:
Utilisation pour
(T item)
:null
renvoie false.la source
Le changement est un peu lent, car chaque fois que les méthodes dans la pire des situations passeront par tous les types. Je pense que l'utilisation de Dictonary est plus agréable, dans cette situation, vous aurez
O(1)
:la source
Essayez le package nuget TypeSupport pour C #. Il prend en charge la détection de tous les types numériques (parmi de nombreuses autres fonctionnalités):
la source
Malheureusement, ces types n'ont pas grand-chose en commun à part ce sont tous des types de valeur. Mais pour éviter un long cas de commutation, vous pouvez simplement définir une liste en lecture seule avec tous ces types et ensuite simplement vérifier si le type donné est dans la liste.
la source
Ce sont tous des types de valeur (sauf pour bool et peut-être enum). Vous pouvez donc simplement utiliser:
la source
struct
... Je ne pense pas que ce soit ce que vous voulez.EDIT: Eh bien, j'ai modifié le code ci-dessous pour être plus performant, puis j'ai exécuté les tests postés par @Hugo contre lui. Les vitesses sont à peu près équivalentes à celles de @ Hugo en utilisant le dernier élément de sa séquence (Decimal). Cependant, si vous utilisez le premier élément «octet», il prend le gâteau, mais l'ordre est clairement important en termes de performances. Bien que l'utilisation du code ci-dessous soit plus facile à écrire et plus cohérente en termes de coût, elle n'est cependant pas maintenable ou à l'épreuve du futur.
On dirait que le passage de Type.GetTypeCode () à Convert.GetTypeCode () a accéléré considérablement les performances, environ 25%, VS Enum.Parse () qui était 10 fois plus lent.
Je sais que ce post est vieux , mais IF en utilisant la méthode ENUM TypeCode, plus facile (et probablement le moins cher) serait quelque chose comme ceci:
Étant donné la définition d'énumération suivante pour TypeCode:
Je ne l'ai pas testé à fond, mais pour les types numériques de base C #, cela semble le couvrir. Cependant, comme @JonSkeet l'a mentionné, cette énumération n'est pas mise à jour pour les types supplémentaires ajoutés à .NET ultérieurement.
la source
Oups! J'ai mal lu la question! Personnellement, je roulerais avec Skeet .
hrm, ressemble à ce que vous voulez
DoSomething
surType
vos données. Ce que vous pourriez faire est ce qui suitla source