Hier ist eine Methode, die feststellt, ob ein bestimmter Wert, der in einem generischen numerischen Typ gespeichert ist, eine ganze Zahl ist, ohne hart zu kodieren. Funktioniert bei mir unter .NET 4. Behandelt korrekt alle eingebauten numerischen Typen (wie im MSDN-Link unten definiert) außer BigInteger
die nicht implementiert IConvertible
.
public static bool? IsInteger<T>(T testNumber) where T : IConvertible
{
// returns null if T is non-numeric
bool? isInt = null;
try
{
isInt = testNumber.ToUInt64(CultureInfo.InvariantCulture) == testNumber.ToDouble(CultureInfo.InvariantCulture);
}
catch (OverflowException)
{
// casting a negative int will cause this exception
try
{
isInt = testNumber.ToInt64(CultureInfo.InvariantCulture) == testNumber.ToDouble(CultureInfo.InvariantCulture);
}
catch
{
// throw depending on desired behavior
}
}
catch
{
// throw depending on desired behavior
}
return isInt;
}
Hier ist eine Methode, mit der festgestellt werden kann, ob ein bestimmter Typ ein Integraltyp ist.
public static bool? IsIntegerType<T>() where T : IConvertible
{
bool? isInt = null;
try
{
isInt = Math.Round((double)Convert.ChangeType((T)Convert.ChangeType(0.1d, typeof(T)),typeof(double)), 1) != .1d;
// if you don't round it and T is float you'll get the wrong result
}
catch
{
// T is a non numeric type, or something went wrong with the activator
}
return isInt;
}
Convert.ChangeType
ist der Weg zur Konvertierung zwischen zwei generischen numerischen Typen mit Rundung. Aber zum Spaß und aus Neugierde, hier ist ein Weg, um einen generischen numerischen Typ in einen int
die ohne allzu große Schwierigkeiten erweitert werden könnte, um einen generischen Typ zurückzugeben.
public static int GetInt32<T>(T target) where T : IConvertible
{
bool? isInt = IsInteger<T>(target);
if (isInt == null) throw new ArgumentException(); // put an appropriate message in
else if (isInt == true)
{
try
{
int i = target.ToInt32(CultureInfo.InvariantCulture);
return i;
}
catch
{ // exceeded size of int32
throw new OverflowException(); // put an appropriate message in
}
}
else
{
try
{
double d = target.ToDouble(CultureInfo.InvariantCulture);
return (int)Math.Round(d);
}
catch
{ // exceeded size of int32
throw new OverflowException(); // put an appropriate message in
}
}
}
Meine Ergebnisse:
double d = 1.9;
byte b = 1;
sbyte sb = 1;
float f = 2.0f;
short s = 1;
int i = -3;
UInt16 ui = 44;
ulong ul = ulong.MaxValue;
bool? dd = IsInteger<double>(d); // false
bool? dt = IsInteger<DateTime>(DateTime.Now); // null
bool? db = IsInteger<byte>(b); // true
bool? dsb = IsInteger<sbyte>(sb); // true
bool? df = IsInteger<float>(f); // true
bool? ds = IsInteger<short>(s); // true
bool? di = IsInteger<int>(i); // true
bool? dui = IsInteger<UInt16>(ui); // true
bool? dul = IsInteger<ulong>(ul); // true
int converted = GetInt32<double>(d); // coverted==2
bool? isd = IsIntegerType<double>(); // false
bool? isi = IsIntegerType<int>(); // true
Zusätzlich, diese MSDN-Seite hat einige Beispielcodes, die hilfreich sein könnten. Er enthält insbesondere eine Liste von Typen, die als numerisch gelten.