簡體   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