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.
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.
Réponses:
Essaye ça:
Type type = object.GetType();
bool isNumber = (type.IsPrimitiveImple && type != typeof(bool) && type != typeof(char));
Les types primitifs sont Boolean, Byte, SByte, Int16, UInt16, Int32, UInt32, Int64, UInt64, Char, Double et Single.
Poussant un peu plus loin la solution de Guillaume :
public static bool IsNumericType(this object o)
{
switch (Type.GetTypeCode(o.GetType()))
{
case TypeCode.Byte:
case TypeCode.SByte:
case TypeCode.UInt16:
case TypeCode.UInt32:
case TypeCode.UInt64:
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.Int64:
case TypeCode.Decimal:
case TypeCode.Double:
case TypeCode.Single:
return true;
default:
return false;
}
}
Usage:
int i = 32;
i.IsNumericType(); // True
string s = "Hello World";
s.IsNumericType(); // False
decimaltype 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:
HashSet<Type> NumericTypes = new HashSet<Type>
{
typeof(decimal), typeof(byte), typeof(sbyte),
typeof(short), typeof(ushort), ...
};
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.
switchcela ne fonctionne tout simplement pas Type, donc vous ne pouvez pas. Vous pouvez TypeCodebien 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:
private static HashSet<Type> NumericTypes = new HashSet<Type>
{
typeof(int),
typeof(uint),
typeof(double),
typeof(decimal),
...
};
internal static bool IsNumericType(Type type)
{
return NumericTypes.Contains(type) ||
NumericTypes.Contains(Nullable.GetUnderlyingType(type));
}
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.
private static HashSet<Type> NumericTypes = new HashSet<Type>
{
typeof(int),
typeof(int?),
...
};
public static bool IsNumericType(Type type)
{
switch (Type.GetTypeCode(type))
{
case TypeCode.Byte:
case TypeCode.SByte:
case TypeCode.UInt16:
case TypeCode.UInt32:
case TypeCode.UInt64:
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.Int64:
case TypeCode.Decimal:
case TypeCode.Double:
case TypeCode.Single:
return true;
default:
return false;
}
}
Remarque sur l'optimisation supprimée (voir les commentaires enzi)
Et si vous voulez vraiment l'optimiser (perte de lisibilité et de sécurité ...):
public static bool IsNumericType(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;
}
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:
public static class TypeHelper
{
private static readonly HashSet<Type> NumericTypes = new HashSet<Type>
{
typeof(int), typeof(double), typeof(decimal),
typeof(long), typeof(short), typeof(sbyte),
typeof(byte), typeof(ulong), typeof(ushort),
typeof(uint), typeof(float)
};
public static bool IsNumeric(Type myType)
{
return NumericTypes.Contains(Nullable.GetUnderlyingType(myType) ?? myType);
}
}
Approche basée sur la proposition de Philip , améliorée avec la vérification de type interne de SFun28 pour les Nullabletypes:
public static class IsNumericType
{
public static bool IsNumeric(this Type type)
{
switch (Type.GetTypeCode(type))
{
case TypeCode.Byte:
case TypeCode.SByte:
case TypeCode.UInt16:
case TypeCode.UInt32:
case TypeCode.UInt64:
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.Int64:
case TypeCode.Decimal:
case TypeCode.Double:
case TypeCode.Single:
return true;
case TypeCode.Object:
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
{
return Nullable.GetUnderlyingType(type).IsNumeric();
//return IsNumeric(Nullable.GetUnderlyingType(type));
}
return false;
default:
return false;
}
}
}
Pourquoi ça? J'ai dû vérifier si un donné Type typeest un type numérique, et non si un arbitraire object oest numérique.
Avec C # 7, cette méthode me donne de meilleures performances que d'activer le boîtier TypeCodeet HashSet<Type>:
public static bool IsNumeric(this object o) => o is byte || o is sbyte || o is ushort || o is uint || o is ulong || o is short || o is int || o is long || o is float || o is double || o is decimal;
Les tests sont les suivants:
public static class Extensions
{
public static HashSet<Type> NumericTypes = new HashSet<Type>()
{
typeof(byte), typeof(sbyte), typeof(ushort), typeof(uint), typeof(ulong), typeof(short), typeof(int), typeof(long), typeof(decimal), typeof(double), typeof(float)
};
public static bool IsNumeric1(this object o) => NumericTypes.Contains(o.GetType());
public static bool IsNumeric2(this object o) => o is byte || o is sbyte || o is ushort || o is uint || o is ulong || o is short || o is int || o is long || o is decimal || o is double || o is float;
public static bool IsNumeric3(this object o)
{
switch (o)
{
case Byte b:
case SByte sb:
case UInt16 u16:
case UInt32 u32:
case UInt64 u64:
case Int16 i16:
case Int32 i32:
case Int64 i64:
case Decimal m:
case Double d:
case Single f:
return true;
default:
return false;
}
}
public static bool IsNumeric4(this object o)
{
switch (Type.GetTypeCode(o.GetType()))
{
case TypeCode.Byte:
case TypeCode.SByte:
case TypeCode.UInt16:
case TypeCode.UInt32:
case TypeCode.UInt64:
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.Int64:
case TypeCode.Decimal:
case TypeCode.Double:
case TypeCode.Single:
return true;
default:
return false;
}
}
}
class Program
{
static void Main(string[] args)
{
var count = 100000000;
//warm up calls
for (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 here
var sw = new Stopwatch();
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);
}
Vous pouvez utiliser Type.IsPrimitive , puis trier les types Booleanet Char, quelque chose comme ceci:
bool IsNumeric(Type type)
{
return type.IsPrimitive && type!=typeof(char) && type!=typeof(bool);
}
EDIT : Vous pouvez exclure les IntPtret UIntPtrtypes aussi bien, si vous ne les considérez pas comme numérique.
decimaltype n'est pas numérique?
Extension de type avec prise en charge de type nul.
public static bool IsNumeric(this Type type)
{
if (type == null) { return false; }
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
{
type = type.GetGenericArguments()[0];
}
switch (Type.GetTypeCode(type))
{
case TypeCode.Byte:
case TypeCode.SByte:
case TypeCode.UInt16:
case TypeCode.UInt32:
case TypeCode.UInt64:
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.Int64:
case TypeCode.Decimal:
case TypeCode.Double:
case TypeCode.Single:
return true;
default:
return false;
}
}
L' utilisation de modification au pigeon d' argile et la solution de arviman Generics, Reflectionet C# v6.0.
private static readonly HashSet<Type> m_numTypes = new HashSet<Type>
{
typeof(int), typeof(double), typeof(decimal),
typeof(long), typeof(short), typeof(sbyte),
typeof(byte), typeof(ulong), typeof(ushort),
typeof(uint), typeof(float), typeof(BigInteger)
};
Suivi par:
public static bool IsNumeric<T>( this T myType )
{
var IsNumeric = false;
if( myType != null )
{
IsNumeric = m_numTypes.Contains( myType.GetType() );
}
return IsNumeric;
}
Utilisation pour (T item):
if ( item.IsNumeric() ) {}
null renvoie false.
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):
public static class TypeExtensions
{
private static readonly HashSet<Type> NumberTypes = new HashSet<Type>();
static TypeExtensions()
{
NumberTypes.Add(typeof(byte));
NumberTypes.Add(typeof(decimal));
NumberTypes.Add(typeof(double));
NumberTypes.Add(typeof(float));
NumberTypes.Add(typeof(int));
NumberTypes.Add(typeof(long));
NumberTypes.Add(typeof(sbyte));
NumberTypes.Add(typeof(short));
NumberTypes.Add(typeof(uint));
NumberTypes.Add(typeof(ulong));
NumberTypes.Add(typeof(ushort));
}
public static bool IsNumber(this Type type)
{
return NumberTypes.Contains(type);
}
}
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);
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.
Ce sont tous des types de valeur (sauf pour bool et peut-être enum). Vous pouvez donc simplement utiliser:
bool IsNumberic(object o)
{
return (o is System.ValueType && !(o is System.Boolean) && !(o is System.Enum))
}
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:
public static bool IsNumericType(this object o)
{
var t = (byte)Convert.GetTypeCode(o);
return t > 4 && t < 16;
}
Étant donné la définition d'énumération suivante pour TypeCode:
public enum TypeCode
{
Empty = 0,
Object = 1,
DBNull = 2,
Boolean = 3,
Char = 4,
SByte = 5,
Byte = 6,
Int16 = 7,
UInt16 = 8,
Int32 = 9,
UInt32 = 10,
Int64 = 11,
UInt64 = 12,
Single = 13,
Double = 14,
Decimal = 15,
DateTime = 16,
String = 18
}
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
public class MyClass
{
private readonly Dictionary<Type, Func<SomeResult, object>> _map =
new Dictionary<Type, Func<SomeResult, object>> ();
public MyClass ()
{
_map.Add (typeof (int), o => return SomeTypeSafeMethod ((int)(o)));
}
public SomeResult DoSomething<T>(T numericValue)
{
Type valueType = typeof (T);
if (!_map.Contains (valueType))
{
throw new NotSupportedException (
string.Format (
"Does not support Type [{0}].", valueType.Name));
}
SomeResult result = _map[valueType] (numericValue);
return result;
}
}