Gibt es eine Möglichkeit festzustellen, ob ein bestimmter .NET-Typ eine Zahl ist oder nicht? Zum Beispiel: System.UInt32/UInt16/Doublesind alle Zahlen. Ich möchte einen langen Schaltkasten am vermeiden Type.FullName.
@ Xaero: Ich habe keinen Zweifel, dass decimaldas numerisch ist. Nur weil es kein Primitiv ist, heißt das nicht, dass es nicht numerisch ist. Ihr Code muss dies berücksichtigen.
LukeH
2
Dies müsste für die neuen numerischen Typen in .NET 4.0 ohne Typcodes überarbeitet werden.
Jon Skeet
7
Wie können Sie mich auf eine Antwort abstimmen, die auf der aktuellen Technologie basiert? Vielleicht wird in .NET 62 int entfernt - werden Sie alle Antworten mit int herabstimmen?
Philip Wallace
1
@ DiskJunky Sorry, Freund. Das war vor fast drei Jahren und ich erinnere mich nicht, was ihr Inhalt war.
Kdbanman
93
Verwenden Sie keinen Schalter - verwenden Sie einfach ein Set:
BEARBEITEN: Ein Vorteil gegenüber der Verwendung eines Typcodes besteht darin, dass bei der Einführung neuer numerischer Typen in .NET (z. B. BigInteger und Complex ) die Anpassung einfach ist - während diese Typen keinen Typcode erhalten.
Hätte gedacht, der Compiler würde eine implizite Konvertierung der switch-Anweisung in hashset durchführen.
Rolf Kristensen
6
@RolfKristensen: Nun switch, funktioniert einfach nicht Type, also kannst du nicht. Sie können TypeCodenatürlich einschalten , aber das ist eine andere Sache.
Ich weiß, ich könnte einfach die Nullables selbst zu meinem HashSet hinzufügen. Diese Lösung vermeidet jedoch die Gefahr, dass Sie vergessen, Ihrer Liste eine bestimmte Nullable hinzuzufügen.
Ist ein nullbarer Typ wirklich numerisch? Null ist meines Wissens keine Zahl.
IllidanS4 will Monica
2
Das hängt davon ab, was Sie erreichen wollen. In meinem Fall musste ich auch Nullables einschließen. Ich könnte mir aber auch Situationen vorstellen, in denen dies kein gewünschtes Verhalten ist.
Jürgen Steinblock
Gut! Die Behandlung einer nullbaren Zahl als Zahl ist bei der Validierung von UI-Eingaben sehr nützlich.
Guogangj
1
@ IllidanS4 Die Prüfung ist auf Typ, nicht der Wert. In den meisten Fällen sollten nullfähige numerische Typen als numerisch behandelt werden. Wenn die Prüfung auf Wert war und der Wert null ist, sollte sie natürlich nicht als numerisch betrachtet werden.
Hinweis zur Optimierung entfernt (siehe enzi-Kommentare)
Und wenn Sie es wirklich optimieren möchten (Lesbarkeit und Sicherheit verlieren ...):
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;}
Ich weiß, dass diese Antwort alt ist, aber ich bin kürzlich auf einen solchen Schalter gestoßen: Verwenden Sie nicht die vorgeschlagene Optimierung! Ich habe mir den IL-Code angesehen, der von einem solchen Schalter generiert wurde, und festgestellt, dass der Compiler die Optimierung bereits anwendet (in IL 5 wird vom Typcode subtrahiert und dann werden Werte von 0 bis 10 als wahr betrachtet). Daher sollte der Schalter verwendet werden, um besser lesbar, sicherer und genauso schnell zu sein.
Enzi
1
Wenn Sie es tatsächlich optimieren möchten und sich nicht um die Lesbarkeit kümmern möchten, würde der optimale Code return unchecked((uint)Type.GetTypeCode(type) - 5u) <= 10u;den von eingeführten Zweig entfernen &&.
AnorZaken
14
Grundsätzlich Skeets Lösung, aber Sie können sie mit Nullable-Typen wie folgt wiederverwenden:
Mit C # 7 bietet mir diese Methode eine bessere Leistung als das Einschalten des Gehäuses TypeCodeund 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;
Tests sind folgende:
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);}
Tatsache ist, dass viele verschiedene Typen in C # numerische Daten enthalten können. Sofern Sie nicht wissen, was Sie erwartet (Int, Double usw.), müssen Sie die "long" case-Anweisung verwenden.
Der Wechsel ist etwas langsam, da jedes Mal, wenn Methoden in der schlimmsten Situation alle Arten durchlaufen. Ich denke, Dictonary zu verwenden ist schöner, in dieser Situation haben Sie O(1):
Ich kannte dieses Paket nicht. Scheint in vielen Fällen ein Lebensretter zu sein, um zu vermeiden, unseren eigenen Code für die vom OP angeforderten Operationen zu schreiben. Vielen Dank !
Nach dem
0
Leider haben diese Typen nicht viel gemeinsam, außer dass sie alle Werttypen sind. Um einen langen Wechsel zu vermeiden, können Sie einfach eine schreibgeschützte Liste mit all diesen Typen definieren und dann überprüfen, ob der angegebene Typ in der Liste enthalten ist.
Dies wird für alle benutzerdefinierten Werte "true struct" zurückgeben. Ich glaube nicht, dass Sie dies wünschen.
Dan Tao
1
Du hast Recht. Eingebaute numerische Typen sind ebenfalls Strukturen. Gehen Sie also besser zum primitiven Vergleich.
MandoMando
0
EDIT: Nun, ich habe den folgenden Code geändert, um eine bessere Leistung zu erzielen, und dann die von @Hugo veröffentlichten Tests dagegen ausgeführt. Die Geschwindigkeiten sind ungefähr gleich hoch wie bei @ Hugos IF, wenn das letzte Element in seiner Sequenz (Dezimal) verwendet wird. Wenn Sie jedoch das erste Element "Byte" verwenden, nimmt er den Kuchen, aber die Reihenfolge ist eindeutig wichtig, wenn es um die Leistung geht. Die Verwendung des folgenden Codes ist zwar einfacher zu schreiben und hinsichtlich der Kosten konsistenter, jedoch nicht wartbar oder zukunftssicher.
Der Wechsel von Type.GetTypeCode () zu Convert.GetTypeCode () hat die Leistung drastisch beschleunigt, etwa 25% gegenüber VS Enum.Parse (), was etwa zehnmal langsamer war.
Ich weiß , dass dieser Beitrag ist alt, aber IF die Typecode - Enumeration - Methode, einfachste (und wahrscheinlich das billigste) würde wie folgt sein:
publicstaticboolIsNumericType(thisobject o){var t =(byte)Convert.GetTypeCode(o);return t >4&& t <16;}
Angesichts der folgenden Aufzählungsdefinition für TypeCode:
Ich habe es nicht gründlich getestet, aber für grundlegende C # -Numeriktypen scheint dies zu reichen. Wie bereits von @JonSkeet erwähnt, wird diese Aufzählung jedoch nicht für zusätzliche Typen aktualisiert, die später zu .NET hinzugefügt werden.
Hoppla! Die Frage falsch verstanden! Persönlich würde mit Skeet rollen .
HRM, klingt wie Sie wollen DoSomethingauf TypeIhre Daten. Was Sie tun könnten, ist das Folgende
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;}}
Antworten:
Versuche dies:Unter Guillaume-Lösung ein wenig weiter:
Verwendung:
quelle
decimal
Typ ist also nicht numerisch?decimal
das numerisch ist. Nur weil es kein Primitiv ist, heißt das nicht, dass es nicht numerisch ist. Ihr Code muss dies berücksichtigen.Verwenden Sie keinen Schalter - verwenden Sie einfach ein Set:
BEARBEITEN: Ein Vorteil gegenüber der Verwendung eines Typcodes besteht darin, dass bei der Einführung neuer numerischer Typen in .NET (z. B. BigInteger und Complex ) die Anpassung einfach ist - während diese Typen keinen Typcode erhalten.
quelle
switch
, funktioniert einfach nichtType
, also kannst du nicht. Sie könnenTypeCode
natürlich einschalten , aber das ist eine andere Sache.Keine der Lösungen berücksichtigt Nullable.
Ich habe Jon Skeets Lösung ein wenig modifiziert:
Ich weiß, ich könnte einfach die Nullables selbst zu meinem HashSet hinzufügen. Diese Lösung vermeidet jedoch die Gefahr, dass Sie vergessen, Ihrer Liste eine bestimmte Nullable hinzuzufügen.
quelle
Hinweis zur Optimierung entfernt (siehe enzi-Kommentare)
Und wenn Sie es wirklich optimieren möchten (Lesbarkeit und Sicherheit verlieren ...):quelle
return unchecked((uint)Type.GetTypeCode(type) - 5u) <= 10u;
den von eingeführten Zweig entfernen&&
.Grundsätzlich Skeets Lösung, aber Sie können sie mit Nullable-Typen wie folgt wiederverwenden:
quelle
Ansatz basierend auf Philipps Vorschlag , erweitert durch die innere Typprüfung von SFun28 für
Nullable
Typen:Warum das? Ich musste überprüfen, ob ein gegebener
Type type
ein numerischer Typ ist und nicht, ob ein beliebiger numerischer Typobject o
ist.quelle
Mit C # 7 bietet mir diese Methode eine bessere Leistung als das Einschalten des Gehäuses
TypeCode
undHashSet<Type>
:Tests sind folgende:
quelle
Sie könnten Type.IsPrimitive verwenden und dann die
Boolean
undChar
-Typen aussortieren, ungefähr so:BEARBEITEN : Möglicherweise möchten Sie auch die Typen
IntPtr
und ausschließenUIntPtr
, wenn Sie sie nicht als numerisch betrachten.quelle
decimal
Typ ist also nicht numerisch?Typerweiterung mit Unterstützung vom Typ Null.
quelle
Kurze Antwort: Nein.
Längere Antwort: Nein.
Tatsache ist, dass viele verschiedene Typen in C # numerische Daten enthalten können. Sofern Sie nicht wissen, was Sie erwartet (Int, Double usw.), müssen Sie die "long" case-Anweisung verwenden.
quelle
Dies kann auch funktionieren. Möglicherweise möchten Sie jedoch einen Typ.Parse verwenden, um ihn anschließend so zu übertragen, wie Sie es möchten.
quelle
Geändert Skeet und arviman-Lösung verwendet
Generics
,Reflection
undC# v6.0
.Gefolgt von:
Verwendung für
(T item)
:null
gibt false zurück.quelle
Der Wechsel ist etwas langsam, da jedes Mal, wenn Methoden in der schlimmsten Situation alle Arten durchlaufen. Ich denke, Dictonary zu verwenden ist schöner, in dieser Situation haben Sie
O(1)
:quelle
Probieren Sie das TypeSupport- Nuget-Paket für C # aus. Es unterstützt die Erkennung aller numerischen Typen (neben vielen anderen Funktionen):
quelle
Leider haben diese Typen nicht viel gemeinsam, außer dass sie alle Werttypen sind. Um einen langen Wechsel zu vermeiden, können Sie einfach eine schreibgeschützte Liste mit all diesen Typen definieren und dann überprüfen, ob der angegebene Typ in der Liste enthalten ist.
quelle
Sie sind alle Werttypen (außer bool und möglicherweise enum). Sie können also einfach Folgendes verwenden:
quelle
struct
" zurückgeben. Ich glaube nicht, dass Sie dies wünschen.EDIT: Nun, ich habe den folgenden Code geändert, um eine bessere Leistung zu erzielen, und dann die von @Hugo veröffentlichten Tests dagegen ausgeführt. Die Geschwindigkeiten sind ungefähr gleich hoch wie bei @ Hugos IF, wenn das letzte Element in seiner Sequenz (Dezimal) verwendet wird. Wenn Sie jedoch das erste Element "Byte" verwenden, nimmt er den Kuchen, aber die Reihenfolge ist eindeutig wichtig, wenn es um die Leistung geht. Die Verwendung des folgenden Codes ist zwar einfacher zu schreiben und hinsichtlich der Kosten konsistenter, jedoch nicht wartbar oder zukunftssicher.
Der Wechsel von Type.GetTypeCode () zu Convert.GetTypeCode () hat die Leistung drastisch beschleunigt, etwa 25% gegenüber VS Enum.Parse (), was etwa zehnmal langsamer war.
Ich weiß , dass dieser Beitrag ist alt, aber IF die Typecode - Enumeration - Methode, einfachste (und wahrscheinlich das billigste) würde wie folgt sein:
Angesichts der folgenden Aufzählungsdefinition für TypeCode:
Ich habe es nicht gründlich getestet, aber für grundlegende C # -Numeriktypen scheint dies zu reichen. Wie bereits von @JonSkeet erwähnt, wird diese Aufzählung jedoch nicht für zusätzliche Typen aktualisiert, die später zu .NET hinzugefügt werden.
quelle
Hoppla! Die Frage falsch verstanden! Persönlich würde mit Skeet rollen .
HRM, klingt wie Sie wollen
DoSomething
aufType
Ihre Daten. Was Sie tun könnten, ist das Folgendequelle