繁体   English   中英

如何在C#中检查(通用)数字类型是否为整数或非整数类型?

[英]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 这样就有了明确的ToDoubleToInteger方法。

编辑

我想我明白了:你有两个局部变量, 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.ChangeTypeMath.Round()慢得多。 理想情况下,我可以检查一次给定类型是否为整数,并Math.Round()起有条件地调用Math.Round()以获得比不断调用Convert.ChangeType()更有效的解决方案。

我正在尝试以下实现:

  1. 都转换321至所需的未知类型。 (这假设可以从int转换为数字类型,无论如何都应该可以。)
  2. 3 / 2 == 1情况下,它是一个整数类型。 否则,它是非整数类型。

此解决方案不依赖于知道类型,只使用转换和计算。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM