[英]How to check whether a (generic) number type is an integral or nonintegral type in C#?
我有一個通用類型T
使用Marc的Operator
類我可以對它進行計算。
也許有更好的解決方案? 我更願意支持任何可能的類型,所以我想防止硬編碼哪些類型是整數/非整數。
背景信息
我發現自己的情況是我想將一個double
精度投射到T
但是將圓的最小值T
舍入到double
值。
int a = (int)2.6
得到2
而我希望它在3
它,而不知道類型(在本例中為int
)。 它也可能是double
,在這種情況下,我希望結果為2.6
。
你試過Convert.ChangeType嗎? 就像是:
Convert.ChangeType(1.9d, typeof (T))
它適用於我認為的所有數字類型(只要第一個參數是iConvertible,類型是支持的,所有基本數字應該是我相信的)。
重要的是要提到這將調用像double.ToInt32這樣的方法來舍入值而不是截斷(我相信銀行家四舍五入)。
我在一個小的LinqPad程序中測試了它,它做了我認為你想要的:
void Main()
{
var foo = RetNum<decimal>();
foo.Dump();
}
public static T RetNum<T>()
{
return (T)Convert.ChangeType(1.9d, typeof (T));
}
這是一種方法,它將確定存儲在通用數字類型中的特定值是否為沒有硬編碼的整數。 測試在.NET上為我工作4.正確處理除BigInteger
之外的所有內置數字類型(如底部的MSDN鏈接中所定義), BigInteger
不實現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;
}
這是一種確定特定類型是否為整數類型的方法。
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
是通過舍入在兩個通用數字類型之間轉換的方式。 但是對於踢腿和好奇心,這里有一種將通用數字類型轉換為int
,可以將其擴展為返回泛型類型而不會有太多困難。
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
}
}
}
我的結果:
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
此外, 此MSDN頁面有一些示例代碼可能會有所幫助。 具體而言,它包括被認為是數字的類型列表。
我不是100%肯定你在問什么,但是:
要檢查它是否是整數類型 ,請使用: if (obj is float || obj is double)
,或者if typeof(T) == typeof(float) || typeof(T) == typeof(double))
if typeof(T) == typeof(float) || typeof(T) == typeof(double))
要檢查它是否為整數值 ,請將其if(value == Math.Round(value))
轉換為double,然后執行if(value == Math.Round(value))
當然,假設您首先有一個數字。 我相信您使用的Operator類支持DateTime之類的東西。 是否更好地使您的泛型方法具有通用約束where T : IConvertible
? 這樣就有了明確的ToDouble
和ToInteger
方法。
編輯 :
我想我明白了:你有兩個局部變量, double d; T num;
double d; T num;
。 您希望將d
為類型T
,但如果T
是整數類型,則使用適當的舍入。 那是對的嗎?
假設這是正確的,這就是我要做的:
public void SomeMethod<T>()
{
double d;
// I think I got all the floating-point types. There's only a few, so we can test for them explicitly.
if(typeof(T) != typeof(double) && typeof(T) != typeof(float) && typeof(T) != typeof(Decimal))
{
d = Math.Round(d);
}
T converted = Convert.ChangeType(d, typeof(T));
}
克里斯的回答為我提到的場景提供了一個可能的解決方案,但出於性能原因,我仍然試圖回答實際問題。
假設 (未經測試)是, Convert.ChangeType
比Math.Round()
慢得多。 理想情況下,我可以檢查一次給定類型是否為整數,並Math.Round()
起有條件地調用Math.Round()
以獲得比不斷調用Convert.ChangeType()
更有效的解決方案。
我正在嘗試以下實現:
3
, 2
和1
至所需的未知類型。 (這假設可以從int
轉換為數字類型,無論如何都應該可以。) 3 / 2 == 1
情況下,它是一個整數類型。 否則,它是非整數類型。 此解決方案不依賴於知道類型,只使用轉換和計算。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.