C # - यह निर्धारित करने के लिए कैसे एक प्रकार एक संख्या है


105

क्या यह निर्धारित करने का कोई तरीका है कि क्या कोई दिया गया है या नहीं। .NET प्रकार एक संख्या है? उदाहरण के लिए: System.UInt32/UInt16/Doubleसभी संख्याएँ हैं। मैं एक लंबे स्विच-केस से बचना चाहता हूं Type.FullName


4
बहुतों का डुप्लीकेट, बहुतों का। इसे अभी तक बंद क्यों नहीं किया गया?
नोल्डोरिन

2
का डुप्लीकेट stackoverflow.com/questions/1130698 और बहुत कुछ अन्य लोगों के करीब है।
हेंक होल्टरमैन

जवाबों:


110

इसे इस्तेमाल करे:

Type type = object.GetType();
bool isNumber = (type.IsPrimitiveImple && type != typeof(bool) && type != typeof(char));

आदिम प्रकार बूलियन, बाइट, SByte, Int16, UInt16, Int32, UInt32, Int64, UInt64, चार, डबल और सिंगल हैं।

ले रहा है Guillaume के समाधान थोड़ा आगे:

public static bool IsNumericType(this object o)
{   
  switch (Type.GetTypeCode(o.GetType()))
  {
    case TypeCode.Byte:
    case TypeCode.SByte:
    case TypeCode.UInt16:
    case TypeCode.UInt32:
    case TypeCode.UInt64:
    case TypeCode.Int16:
    case TypeCode.Int32:
    case TypeCode.Int64:
    case TypeCode.Decimal:
    case TypeCode.Double:
    case TypeCode.Single:
      return true;
    default:
      return false;
  }
}

उपयोग:

int i = 32;
i.IsNumericType(); // True

string s = "Hello World";
s.IsNumericType(); // False

2
तो decimalप्रकार संख्यात्मक नहीं है?
ल्यूक

2
@Xaero: मुझे कोई संदेह नहीं है कि राशि decimal है सांख्यिक। सिर्फ इसलिए कि यह एक आदिम नहीं है इसका मतलब यह नहीं है कि यह संख्यात्मक नहीं है। इसके लिए आपके कोड की आवश्यकता है।
ल्यूक

2
इसे .NET 4.0 में नए सांख्यिक प्रकारों के लिए फिर से इंजीनियर होना होगा जिनके पास टाइप कोड नहीं हैं।
जॉन स्कीट

7
वर्तमान तकनीक पर आधारित उत्तर पर आप मुझे कैसे नीचा दिखा सकते हैं। शायद .NET 62 में, int हटा दिया जाएगा - क्या आप int के साथ सभी उत्तरों को डाउनवोट करने जा रहे हैं?
फिलिप वैलेस

1
@DiskJunky क्षमा करें, मित्र। यह लगभग तीन साल पहले था और मुझे याद नहीं है कि उनकी सामग्री क्या थी।
kdbanman

93

एक स्विच का उपयोग न करें - बस एक सेट का उपयोग करें:

HashSet<Type> NumericTypes = new HashSet<Type>
{
    typeof(decimal), typeof(byte), typeof(sbyte),
    typeof(short), typeof(ushort), ...
};

EDIT: एक प्रकार के कोड का उपयोग करने पर इसका एक फायदा यह है कि जब नए संख्यात्मक प्रकारों को .NET (जैसे BigInteger और Complex ) में पेश किया जाता है, तो इसे समायोजित करना आसान होता है - जबकि उन प्रकारों को एक प्रकार का कोड नहीं मिलेगा।


4
और आप हैशसेट का उपयोग कैसे करेंगे?
आरवीकेके

8
NumericTypes.Contains (जो)?
एमकेपी

3
bool isanumber = NumericTypes.Contains (classInstance.GetType ());
यूरी फकटोरोविच

सोचा होगा कि कंपाइलर स्विच-स्टेटमेंट का एक अंतर्निहित रूपांतरण हैशसेट में करेगा।
रॉल्फ क्रिस्टेन्सन

6
@ रॉल्फक्रिस्टेंसन: अच्छी तरह से switchबस काम नहीं करता है Type, इसलिए आप नहीं कर सकते। आप TypeCodeबेशक बदल सकते हैं , लेकिन यह एक अलग मामला है।
जॉन स्कीट

69

कोई भी समाधान Nullable को ध्यान में नहीं रखता है।

मैंने जॉन स्कीट के समाधान को थोड़ा संशोधित किया:

    private static HashSet<Type> NumericTypes = new HashSet<Type>
    {
        typeof(int),
        typeof(uint),
        typeof(double),
        typeof(decimal),
        ...
    };

    internal static bool IsNumericType(Type type)
    {
        return NumericTypes.Contains(type) ||
               NumericTypes.Contains(Nullable.GetUnderlyingType(type));
    }

मुझे पता है कि मैं केवल अपने हैशसेट में अशक्त जोड़ सकते हैं। लेकिन यह समाधान आपकी सूची में एक विशिष्ट अशक्त जोड़ने के लिए भूलने के खतरे से बचता है।

    private static HashSet<Type> NumericTypes = new HashSet<Type>
    {
        typeof(int),
        typeof(int?),
        ...
    };

2
क्या एक अशक्त प्रकार वास्तव में संख्यात्मक है? मेरे ज्ञान के लिए अशक्त संख्या नहीं है।
IllidanS4 मोनिका

2
यह इस बात पर निर्भर करता है कि आप क्या हासिल करना चाहते हैं। मेरे मामले में मुझे nullables भी शामिल करने की आवश्यकता थी। लेकिन मैं उन स्थितियों के बारे में भी सोच सकता था जहां यह एक वांछित व्यवहार नहीं है।
जुरगेन स्टाइनब्लॉक

अच्छा! शून्य संख्या का इलाज करने के लिए संख्या यूआई इनपुट सत्यापन में बहुत उपयोगी है।
गुगंज

1
@ IllidanS4 यह चेक टाइप पर है मान नहीं। ज्यादातर मामलों में अशक्त संख्यात्मक प्रकारों को संख्यात्मक के रूप में माना जाना चाहिए। बेशक अगर चेक मूल्य पर था और मूल्य शून्य है, तो हाँ इसे संख्यात्मक नहीं माना जाना चाहिए।
नवाफल

40
public static bool IsNumericType(Type type)
{
  switch (Type.GetTypeCode(type))
  {
    case TypeCode.Byte:
    case TypeCode.SByte:
    case TypeCode.UInt16:
    case TypeCode.UInt32:
    case TypeCode.UInt64:
    case TypeCode.Int16:
    case TypeCode.Int32:
    case TypeCode.Int64:
    case TypeCode.Decimal:
    case TypeCode.Double:
    case TypeCode.Single:
      return true;
    default:
      return false;
  }
}

हटाए गए अनुकूलन के बारे में ध्यान दें (enzi टिप्पणियाँ देखें) और यदि आप वास्तव में इसे अनुकूलित करना चाहते हैं (पठनीयता और कुछ सुरक्षा खोना ...):

public static bool IsNumericType(Type type)
{
  TypeCode typeCode = Type.GetTypeCode(type);
  //The TypeCode of numerical types are between SByte (5) and Decimal (15).
  return (int)typeCode >= 5 && (int)typeCode <= 15;
}


13
मुझे पता है कि यह उत्तर पुराना है, लेकिन मैं हाल ही में इस तरह के एक स्विच में आया था: सुझाए गए अनुकूलन का उपयोग न करें! मैंने ऐसे स्विच से उत्पन्न IL कोड को देखा, और नोट किया कि संकलक पहले से ही अनुकूलन लागू करता है (IL 5 में टाइप कोड से घटाया जाता है और फिर 0 से 10 तक के मानों को सत्य माना जाता है)। इसलिए यह स्विच अधिक पठनीय और सुरक्षित है और बस उपवास के लिए उपयोग किया जाना चाहिए।
enzi

1
यदि आप वास्तव में इसे अनुकूलित करना चाहते हैं और पठनीयता की परवाह नहीं करते हैं तो इष्टतम कोड return unchecked((uint)Type.GetTypeCode(type) - 5u) <= 10u;इस प्रकार शुरू की गई शाखा को हटा देगा &&

14

मूल रूप से स्कीट का समाधान लेकिन आप इसे निम्न प्रकार से अशक्त प्रकारों के साथ फिर से उपयोग कर सकते हैं:

public static class TypeHelper
{
    private static readonly HashSet<Type> NumericTypes = new HashSet<Type>
    {
        typeof(int),  typeof(double),  typeof(decimal),
        typeof(long), typeof(short),   typeof(sbyte),
        typeof(byte), typeof(ulong),   typeof(ushort),  
        typeof(uint), typeof(float)
    };

    public static bool IsNumeric(Type myType)
    {
       return NumericTypes.Contains(Nullable.GetUnderlyingType(myType) ?? myType);
    }
}

9

फिलिप के प्रस्ताव के आधार पर दृष्टिकोण , SFun28 के आंतरिक प्रकार के Nullableप्रकारों के लिए बढ़ाया गया :

public static class IsNumericType
{
    public static bool IsNumeric(this Type type)
    {
        switch (Type.GetTypeCode(type))
        {
            case TypeCode.Byte:
            case TypeCode.SByte:
            case TypeCode.UInt16:
            case TypeCode.UInt32:
            case TypeCode.UInt64:
            case TypeCode.Int16:
            case TypeCode.Int32:
            case TypeCode.Int64:
            case TypeCode.Decimal:
            case TypeCode.Double:
            case TypeCode.Single:
                return true;
            case TypeCode.Object:
                if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
                {
                    return Nullable.GetUnderlyingType(type).IsNumeric();
                    //return IsNumeric(Nullable.GetUnderlyingType(type));
                }
                return false;
            default:
                return false;
        }
    }
}

यही कारण है? मुझे यह जांचना था कि क्या दिया गया Type typeएक संख्यात्मक प्रकार है, और यदि कोई मनमाना object oसंख्यात्मक नहीं है।


4

C # 7 के साथ यह विधि मुझे स्विच केस की तुलना में बेहतर प्रदर्शन देती है TypeCodeऔर HashSet<Type>:

public static bool IsNumeric(this object o) => o is byte || o is sbyte || o is ushort || o is uint || o is ulong || o is short || o is int || o is long || o is float || o is double || o is decimal;

परीक्षण निम्नलिखित हैं:

public static class Extensions
{
    public static HashSet<Type> NumericTypes = new HashSet<Type>()
    {
        typeof(byte), typeof(sbyte), typeof(ushort), typeof(uint), typeof(ulong), typeof(short), typeof(int), typeof(long), typeof(decimal), typeof(double), typeof(float)
    };

    public static bool IsNumeric1(this object o) => NumericTypes.Contains(o.GetType());

    public static bool IsNumeric2(this object o) => o is byte || o is sbyte || o is ushort || o is uint || o is ulong || o is short || o is int || o is long || o is decimal || o is double || o is float;

    public static bool IsNumeric3(this object o)
    {
        switch (o)
        {
            case Byte b:
            case SByte sb:
            case UInt16 u16:
            case UInt32 u32:
            case UInt64 u64:
            case Int16 i16:
            case Int32 i32:
            case Int64 i64:
            case Decimal m:
            case Double d:
            case Single f:
                return true;
            default:
                return false;
        }
    }

    public static bool IsNumeric4(this object o)
    {
        switch (Type.GetTypeCode(o.GetType()))
        {
            case TypeCode.Byte:
            case TypeCode.SByte:
            case TypeCode.UInt16:
            case TypeCode.UInt32:
            case TypeCode.UInt64:
            case TypeCode.Int16:
            case TypeCode.Int32:
            case TypeCode.Int64:
            case TypeCode.Decimal:
            case TypeCode.Double:
            case TypeCode.Single:
                return true;
            default:
                return false;
        }
    }
}

class Program
{
    static void Main(string[] args)
    {           
        var count = 100000000;

        //warm up calls
        for (var i = 0; i < count; i++)
        {
            i.IsNumeric1();
        }
        for (var i = 0; i < count; i++)
        {
            i.IsNumeric2();
        }
        for (var i = 0; i < count; i++)
        {
            i.IsNumeric3();
        }
        for (var i = 0; i < count; i++)
        {
            i.IsNumeric4();
        }

        //Tests begin here
        var sw = new Stopwatch();
        sw.Restart();
        for (var i = 0; i < count; i++)
        {
            i.IsNumeric1();
        }
        sw.Stop();

        Debug.WriteLine(sw.ElapsedMilliseconds);

        sw.Restart();
        for (var i = 0; i < count; i++)
        {
            i.IsNumeric2();
        }
        sw.Stop();

        Debug.WriteLine(sw.ElapsedMilliseconds);

        sw.Restart();
        for (var i = 0; i < count; i++)
        {
            i.IsNumeric3();
        }
        sw.Stop();

        Debug.WriteLine(sw.ElapsedMilliseconds);

        sw.Restart();
        for (var i = 0; i < count; i++)
        {
            i.IsNumeric4();
        }
        sw.Stop();

        Debug.WriteLine(sw.ElapsedMilliseconds);
    }

3

आप इस्तेमाल कर सकते हैं Type.IsPrimitive और फिर बाहर प्रकार Booleanऔर Charप्रकार, कुछ इस तरह:

bool IsNumeric(Type type)
{
    return type.IsPrimitive && type!=typeof(char) && type!=typeof(bool);
}

संपादित करें : यदि आप उन्हें संख्यात्मक नहीं मानते हैं, तो आप IntPtrऔर UIntPtrप्रकारों को भी अलग करना चाहते हैं ।


1
तो decimalप्रकार संख्यात्मक नहीं है?
ल्यूक

ऊओप्स ... ठीक है, ऐसा लगता है कि गिलोय का घोल सब के बाद सबसे अच्छा है।
कोनामिमन

3

नल-प्रकार समर्थन के साथ एक्सटेंशन टाइप करें।

public static bool IsNumeric(this Type type)
    {
        if (type == null) { return false; }

        if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
        {
            type = type.GetGenericArguments()[0];
        }

        switch (Type.GetTypeCode(type))
        {
            case TypeCode.Byte:
            case TypeCode.SByte:
            case TypeCode.UInt16:
            case TypeCode.UInt32:
            case TypeCode.UInt64:
            case TypeCode.Int16:
            case TypeCode.Int32:
            case TypeCode.Int64:
            case TypeCode.Decimal:
            case TypeCode.Double:
            case TypeCode.Single:
                return true;
            default:
                return false;
        }
    }

1

संक्षिप्त उत्तर: नहीं।

दीर्घ उत्तर: नहीं।

तथ्य यह है कि C # में कई अलग-अलग प्रकार के संख्यात्मक डेटा हो सकते हैं। जब तक आप नहीं जानते कि क्या उम्मीद की जाए (इंट, डबल, आदि) आपको "लंबे" केस स्टेटमेंट का उपयोग करने की आवश्यकता है।


1

यह भी काम कर सकता है। हालाँकि, आप इसे बाद में टाइप करने के लिए Type.Parse के साथ इसे फॉलो करना चाहते हैं।

public bool IsNumeric(object value)
{
    float testValue;
    return float.TryParse(value.ToString(), out testValue);
}

1

संशोधित स्कीट की और arviman के समाधान का उपयोग Generics, Reflectionऔर C# v6.0

private static readonly HashSet<Type> m_numTypes = new HashSet<Type>
{
    typeof(int),  typeof(double),  typeof(decimal),
    typeof(long), typeof(short),   typeof(sbyte),
    typeof(byte), typeof(ulong),   typeof(ushort),
    typeof(uint), typeof(float),   typeof(BigInteger)
};

के बाद:

public static bool IsNumeric<T>( this T myType )
{
    var IsNumeric = false;

    if( myType != null )
    {
        IsNumeric = m_numTypes.Contains( myType.GetType() );
    }

    return IsNumeric;
}

के लिए उपयोग (T item):

if ( item.IsNumeric() ) {}

null झूठा लौटता है।


1

स्विच थोड़ा धीमा है, सबसे खराब स्थिति में हर बार तरीकों को शांत करना सभी प्रकार के माध्यम से जाना जाएगा। मुझे लगता है, डिक्टोनरी का उपयोग करना अधिक अच्छा है, इस स्थिति में आपके पास होगा O(1):

public static class TypeExtensions
{
    private static readonly HashSet<Type> NumberTypes = new HashSet<Type>();

    static TypeExtensions()
    {
        NumberTypes.Add(typeof(byte));
        NumberTypes.Add(typeof(decimal));
        NumberTypes.Add(typeof(double));
        NumberTypes.Add(typeof(float));
        NumberTypes.Add(typeof(int));
        NumberTypes.Add(typeof(long));
        NumberTypes.Add(typeof(sbyte));
        NumberTypes.Add(typeof(short));
        NumberTypes.Add(typeof(uint));
        NumberTypes.Add(typeof(ulong));
        NumberTypes.Add(typeof(ushort));
    }

    public static bool IsNumber(this Type type)
    {
        return NumberTypes.Contains(type);
    }
}

1

C # के लिए TypeSupport नगेट पैकेज आज़माएं । इसमें सभी संख्यात्मक प्रकारों का पता लगाने के लिए समर्थन है (कई अन्य विशेषताओं के बीच):

var extendedType = typeof(int).GetExtendedType();
Assert.IsTrue(extendedType.IsNumericType);

मैं इस पैकेज को नहीं जानता था। ओपी द्वारा अनुरोध किए गए प्रकार के संचालन के लिए अपना खुद का कोड लिखने से बचने के लिए कई मामलों में एक जीवन रक्षक लगता है। धन्यवाद !
10

0

दुर्भाग्य से इन प्रकारों में आम नहीं है, क्योंकि वे सभी मूल्य प्रकार हैं। लेकिन एक लंबे स्विच-केस से बचने के लिए आप इन सभी प्रकारों के साथ एक रीडायनली सूची को परिभाषित कर सकते हैं और फिर यह देख सकते हैं कि सूची में दिया गया प्रकार अंदर है या नहीं।


0

वे सभी मूल्य प्रकार (बूल और शायद एनम को छोड़कर) हैं। तो आप बस का उपयोग कर सकते हैं:

bool IsNumberic(object o)
{
    return (o is System.ValueType && !(o is System.Boolean) && !(o is System.Enum))
}

1
यह किसी भी उपयोगकर्ता-परिभाषित के लिए सही लौटेगा struct... मुझे नहीं लगता कि आप यही चाहते हैं।
डैन ताओ

1
तुम सही हो। अंतर्निहित संख्यात्मक प्रकार के रूप में अच्छी तरह से संरचनात्मक हैं। तो बेहतर तो आदिम तुलना के साथ जाना।
मैंडोमांडो

0

संपादित करें: ठीक है, मैंने नीचे दिए गए कोड को और अधिक प्रदर्शन करने के लिए संशोधित किया और फिर इसके खिलाफ @Hugo द्वारा पोस्ट किए गए परीक्षणों को चलाया। गति के बारे में है @ ह्यूगो IF के साथ अपने अनुक्रम में अंतिम आइटम का उपयोग कर (दशमलव)। यदि पहले आइटम 'बाइट' का उपयोग करते हुए उनका केक लिया जाता है, लेकिन प्रदर्शन के समय यह स्पष्ट रूप से आदेश देता है। हालांकि नीचे दिए गए कोड का उपयोग करना आसान है और इसकी लागत पर अधिक सुसंगत है, हालांकि, यह रखरखाव योग्य या भविष्य के प्रमाण-योग्य नहीं है।

देखने से लगता है कि Type.GetTypeCode () से Convert.GetTypeCode () में लगभग 25%, VS Enum.Parse () जो कि 10 गुना धीमा जैसा था, से स्विच होता है।


मुझे पता है कि यह पोस्ट पुरानी है लेकिन अगर टाइपकोड एनम विधि का उपयोग करना आसान है, (और शायद सबसे सस्ता) कुछ इस तरह होगा:

public static bool IsNumericType(this object o)
{   
  var t = (byte)Convert.GetTypeCode(o);
  return t > 4 && t < 16;
}

TypeCode के लिए निम्नलिखित एनम परिभाषा को देखते हुए:

public enum TypeCode
{
    Empty = 0,
    Object = 1,
    DBNull = 2,
    Boolean = 3,
    Char = 4,
    SByte = 5,
    Byte = 6,
    Int16 = 7,
    UInt16 = 8,
    Int32 = 9,
    UInt32 = 10,
    Int64 = 11,
    UInt64 = 12,
    Single = 13,
    Double = 14,
    Decimal = 15,
    DateTime = 16,
    String = 18
}

मैंने इसका पूरी तरह से परीक्षण नहीं किया है, लेकिन मूल C # संख्यात्मक प्रकारों के लिए, यह इसे कवर करता प्रतीत होगा। हालाँकि, जैसा कि @JonSkeet ने उल्लेख किया है, यह enum सड़क पर .NET को जोड़ने के लिए अतिरिक्त प्रकारों के लिए अद्यतन नहीं है।


-1

उफ़! सवाल गलत! व्यक्तिगत रूप से, स्कीट के साथ रोल करेगा ।


hrm, लगता है जैसे आप अपने डेटा DoSomethingपर करना चाहते हैं Type। आप जो कर सकते थे वह निम्नलिखित है

public class MyClass
{
    private readonly Dictionary<Type, Func<SomeResult, object>> _map = 
        new Dictionary<Type, Func<SomeResult, object>> ();

    public MyClass ()
    {
        _map.Add (typeof (int), o => return SomeTypeSafeMethod ((int)(o)));
    }

    public SomeResult DoSomething<T>(T numericValue)
    {
        Type valueType = typeof (T);
        if (!_map.Contains (valueType))
        {
            throw new NotSupportedException (
                string.Format (
                "Does not support Type [{0}].", valueType.Name));
        }
        SomeResult result = _map[valueType] (numericValue);
        return result;
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.