特定の.Netタイプが数値であるかどうかを判断する方法はありますか?例:System.UInt32/UInt16/Double
はすべて数字です。 Type.FullName
の長いスイッチケースを避けたい。
これを試して:
Type type = object.GetType(); bool isNumber = (type.IsPrimitiveImple && type != typeof(bool) && type != typeof(char));
プリミティブ型は、ブール、バイト、Sバイト、Int16、UInt16、Int32、UInt32、Int64、UInt64、Char、Double、およびSingleです。
ギヨームの解 をもう少し取って:
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;
}
}
使用法:
int i = 32;
i.IsNumericType(); // True
string s = "Hello World";
s.IsNumericType(); // False
スイッチを使用しないでください-セットを使用するだけです:
HashSet<Type> NumericTypes = new HashSet<Type>
{
typeof(decimal), typeof(byte), typeof(sbyte),
typeof(short), typeof(ushort), ...
};
編集:型コードを使用するよりもこの利点の1つは、新しい数値型が.NETに導入されたときに(たとえば BigInteger および Complex )調整しやすいことです-これらの型は、タイプコードを取得しません。
Nullableを考慮に入れるソリューションはありません。
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));
}
Nullables自体をHashSetに追加できることはわかっています。しかし、このソリューションは、リストに特定のNullableを追加することを忘れる危険を回避します。
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;
}
}
最適化に関する注意を削除(エンジコメントを参照) そして、あなたが本当にそれを最適化したいなら(読みやすさといくつかの安全性を失います...):
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; }
基本的にSkeetのソリューションですが、次のようにNullable型で再利用できます。
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);
}
}
Philipの提案 に基づくアプローチ、 SFun28の内部型チェック で強化され、Nullable
型に対して:
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;
}
}
}
なんでこれ?特定のType type
は数値型であり、任意のobject o
は数値です。
C#7では、このメソッドはTypeCode
および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;
テストは次のとおりです。
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);
}
Type.IsPrimitive を使用して、Boolean
およびChar
タイプを次のように整理できます。
bool IsNumeric(Type type)
{
return type.IsPrimitive && type!=typeof(char) && type!=typeof(bool);
}
[〜#〜] edit [〜#〜]:IntPtr
およびUIntPtr
タイプを除外することができます。同様に、数値とみなさない場合。
短い答え:いいえ。
長い回答:いいえ。
実際、C#の多くの異なる型には数値データを含めることができます。予想される内容(Int、Doubleなど)がわからない場合は、「長い」caseステートメントを使用する必要があります。
これもうまくいくかもしれません。ただし、Type.Parseでフォローアップして、後で望むようにキャストすることができます。
public bool IsNumeric(object value)
{
float testValue;
return float.TryParse(value.ToString(), out testValue);
}
編集:さて、私は以下のコードをより高性能に変更し、それに対して@Hugoによって投稿されたテストを実行しました。速度は、シーケンスの最後の項目(10進数)を使用した@HugoのIFとほぼ同等です。しかし、最初のアイテム「バイト」を使用する場合、彼はケーキを取りますが、パフォーマンスに関しては明らかに順序が重要です。以下のコードを使用すると、作成が容易になり、コストの一貫性が高まりますが、保守や将来の証明ができません。
Type.GetTypeCode()からConvert.GetTypeCode()に切り替えると、パフォーマンスが大幅に向上し、約25%、VS Enum.Parse()が10倍遅くなったように見えます。
私はこの投稿が古いことを知っていますが、[〜#〜] if [〜#〜] TypeCode enumメソッドを使用すると、最も簡単な(そしておそらく最も安い)は次のようになります。
public static bool IsNumericType(this object o)
{
var t = (byte)Convert.GetTypeCode(o);
return t > 4 && t < 16;
}
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
}
私はそれを徹底的にテストしていませんが、基本的なC#数値型の場合、これで対応できるようです。ただし、@ JonSkeetが述べたように、この列挙型は、将来的に.NETに追加された追加の型に対しては更新されません。
これらはすべて値型です(boolおよび多分enumを除く)。だからあなたは単に使用することができます:
bool IsNumberic(object o)
{
return (o is System.ValueType && !(o is System.Boolean) && !(o is System.Enum))
}
Generics
、Reflection
、および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)
};
に続く:
public static bool IsNumeric<T>( this T myType )
{
var IsNumeric = false;
if( myType != null )
{
IsNumeric = m_numTypes.Contains( myType.GetType() );
}
return IsNumeric;
}
(T item)
の使用法:
if ( item.IsNumeric() ) {}
null
はfalseを返します。
切り替えは少し遅いですが、最悪の状況での方法がすべてのタイプを通過するたびに原因です。 Dictonaryを使用するほうがいいと思います。この状況では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);
}
}
残念ながら、これらの型はすべて値型である以外に共通点はあまりありません。ただし、長いスイッチケースを回避するには、これらのすべてのタイプで読み取り専用リストを定義し、指定されたタイプがリスト内にあるかどうかを確認するだけです。