我有一个通用类型T
。使用Marc's Operator
class我可以对其进行计算。
是否可以仅通过计算来检测类型是integral还是nonintegral类型?
也许有更好的解决方案?我更愿意支持任何可能的类型,所以我想防止硬编码哪些类型是整数/非整数。
背景信息
我发现自己的情况是,我想将double
转换为T
,但舍入到T
的最近值double
。
int a = (int)2.6
会产生2
,而我希望它在3
中生成,而不知道类型(在本例中为int
)。它也可以是double
,在这种情况下,我希望结果为2.6
。
答案 0 :(得分: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));
}
答案 1 :(得分:3)
这是一种方法,它将确定存储在通用数字类型中的特定值是否为没有硬编码的整数。测试在.NET上为我工作4.正确处理除BigInteger
之外的所有内置数字类型(如底部的MSDN链接中所定义),但不实现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
此外,this MSDN page有一些示例代码可能会有所帮助。具体来说,它包括一个被认为是数字的类型列表。
答案 2 :(得分:2)
我不是100%肯定你在问什么,但是:
要检查它是否为完整的类型,请使用:if (obj is float || obj is double)
或if typeof(T) == typeof(float) || typeof(T) == typeof(double))
要检查它是否为整数值,请将其转换为双精度数,然后执行if(value == Math.Round(value))
当然,假设您首先有一个数字。我相信您使用的Operator类支持DateTime之类的东西。使通用方法具有通用约束where T : IConvertible
会更好吗?这样就会有明确的ToDouble
和ToInteger
方法。
修改强>:
我想我明白了:你有两个局部变量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));
}
答案 3 :(得分:2)
Chris's answer为我提到的场景提供了一个可能的解决方案,但出于性能原因,我仍然试图回答实际问题。
假设(未经测试)是,Convert.ChangeType
比Math.Round()
慢得多。理想情况下,我可以检查一次给定类型是否为完整,并从此开始有条件地调用Math.Round()
以获得比不断调用Convert.ChangeType()
更有效的解决方案。
我尝试以下实施:
3
,2
和1
转换为所需的未知类型。 (这假设可以从int
转换为数字类型,无论如何都应该是可能的。)3 / 2 == 1
的情况下,它是一个整数类型。否则,它是非整数类型。此解决方案并不依赖于知道类型,只使用转换和计算。