जाँच रहा है कि क्या कोई वस्तु C # में एक संख्या है


89

मैं यह जांचना चाहूंगा कि क्या कोई वस्तु एक संख्या है जिससे कि .ToString()अंक वाले स्ट्रिंग में परिणाम होगा +, और -,.

क्या यह .net (जैसे:) में सरल प्रकार की जाँच से संभव है if (p is Number)?

या क्या मुझे स्ट्रिंग में बदलना चाहिए, फिर पार्सिंग को डबल करने की कोशिश करें?

अद्यतन: स्पष्ट करने के लिए मेरी वस्तु int, uint, float, double, और इसी तरह यह एक स्ट्रिंग नहीं है। मैं एक ऐसा फंक्शन बनाने की कोशिश कर रहा हूं, जो किसी भी ऑब्जेक्ट को इस तरह xml में सीरियल करे:

<string>content</string>

या

<numeric>123.3</numeric>

या एक अपवाद बढ़ाएँ।


5
ऐसा लगता है जैसे आप अपना स्वयं का XmlSerializer लिखने की कोशिश कर रहे हैं- .NET- msdn.microsoft.com/en-us/library/… द्वारा एक प्रदाता के साथ क्या गलत है ?
रिचर्ड जूल 15'09

2
आप एक एक्सएसडी का उपयोग करके अपने XML प्रारूप को परिभाषित करके, और फिर एक ऐसी वस्तु का निर्माण कर सकते हैं, जिसमें आप अपने डेटा को एक्सएसडी
Dexter

@ रिचर्ड: क्या मैं एक्सएमएल क्रमांकन का उपयोग वस्तु को अनुक्रमित करने के लिए कर सकता हूं []? मुझे इसे फ़्लैश फंक्शन adobe.com/livedocs/flex/201/html/wwhelp/wwhimpl/common/html/…
Piotr Czapla

जवाबों:


181

आपको बस मूल संख्यात्मक प्रकारों में से प्रत्येक के लिए एक प्रकार की जांच करने की आवश्यकता होगी।

यहाँ एक विस्तार विधि है जो काम करना चाहिए:

public static bool IsNumber(this object value)
{
    return value is sbyte
            || value is byte
            || value is short
            || value is ushort
            || value is int
            || value is uint
            || value is long
            || value is ulong
            || value is float
            || value is double
            || value is decimal;
}

यह सभी संख्यात्मक प्रकारों को कवर करना चाहिए।

अपडेट करें

ऐसा लगता है कि आप वास्तव में deserialisation के दौरान एक स्ट्रिंग से संख्या को पार्स करना चाहते हैं। इस मामले में, यह संभवतः उपयोग करने के लिए सबसे अच्छा होगा double.TryParse

string value = "123.3";
double num;
if (!double.TryParse(value, out num))
    throw new InvalidOperationException("Value is not a number.");

बेशक, यह बहुत बड़े पूर्णांक / लंबे दशमलव को नहीं संभाल पाएगा, लेकिन यदि ऐसा है तो आपको अतिरिक्त कॉल long.TryParse/ decimal.TryParse/ जो भी हो, उसमें जोड़ना होगा ।


मेरी वस्तु int, short, uint, float, double या कुछ और है जो एक संख्या है
पिओटर क्रजाप्ला

@Potr: सही है। ऐसा लगता है कि मैंने आपको गलत समझा। देखिये मेरा अपडेटेड जवाब।
नोल्डोरिन

1
@ नोल्डोरिन: वास्तव में कोड का आपका पिछला संस्करण भी काम करेगा; बस एक शून्य जांच जोड़ें और value.ToString () का उपयोग करें। फिर आपको सभी संख्यात्मक प्रकारों की जांच करने की आवश्यकता नहीं है।
फ्रेड्रिक मोर

1
@Noldorin यह दुख की बात है यह है कि सही समाधान है कि वर्बोज़ :( है।
पिओर Czapla

1
@ जो: वास्तव में, इससे कोई फर्क नहीं पड़ेगा, क्योंकि ToString भी वर्तमान संस्कृति का उपयोग करेगी।
नोल्डोरिन

36

स्कॉट हैनेलमैन के ब्लॉग से लिया गया :

public static bool IsNumeric(object expression)
{
    if (expression == null)
    return false;

    double number;
    return Double.TryParse( Convert.ToString( expression
                                            , CultureInfo.InvariantCulture)
                          , System.Globalization.NumberStyles.Any
                          , NumberFormatInfo.InvariantInfo
                          , out number);
}

6
इस दृष्टिकोण के साथ समस्या यह है कि यदि आप एक स्ट्रिंग में पास होते हैं जो एक संख्या की तरह दिखता है तो यह इसे प्रारूपित करेगा। ज्यादातर लोगों के लिए ठीक हो सकता है लेकिन यह मेरे लिए एक शो स्टॉपर था।
रोब सेडविक

1
इसके साथ एक और संभावित समस्या यह है कि आप डबल के लिए न्यूनतम / अधिकतम मानों को पार्स नहीं कर सकते। double.Parse(double.MaxValue.ToString())एक का कारण बनता है OverflowException। आप .ToString("R")इस मामले में राउंडट्रिप संशोधक प्रदान करके इसका उपाय कर सकते हैं , लेकिन यह ओवरलोड के लिए उपलब्ध नहीं है Convert.ToString(...)क्योंकि हम प्रकार नहीं जानते हैं। मुझे पता है कि यह एक फ्रिंज मामला है, लेकिन मैंने अपने .IsNumeric()विस्तार के लिए परीक्षण लिखते समय इसमें ठोकर खाई । मेरा "समाधान" कुछ भी पार्स करने की कोशिश करने से पहले एक प्रकार की जाँच swtich जोड़ना था, कोड के लिए इस सवाल का मेरा जवाब देखें।
बेन

21

एक उपयोगी एक्सटेंशन विधि बनाने के लिए IsPrimitive संपत्ति का लाभ उठाएं:

public static bool IsNumber(this object obj)
{
    if (Equals(obj, null))
    {
        return false;
    }

    Type objType = obj.GetType();
    objType = Nullable.GetUnderlyingType(objType) ?? objType;

    if (objType.IsPrimitive)
    {
        return objType != typeof(bool) && 
            objType != typeof(char) && 
            objType != typeof(IntPtr) && 
            objType != typeof(UIntPtr);
    }

    return objType == typeof(decimal);
}

संपादित करें: टिप्पणियों के अनुसार फिक्स्ड। .GetType () बॉक्स वैल्यू टाइप के बाद से जेनरिक को हटा दिया गया था। इसमें अशक्त मूल्यों के लिए फिक्स भी शामिल है।


1
जेनरिक पार्ट आपको यहां कोई अतिरिक्त नहीं दे रहा है, क्या यह है? आप केवल GetType () पर
पहुँचते हैं,

अगर एक वैल्यू टाइप पर कॉल किया जाए तो यह एक बॉक्स ऑपरेशन को सेव करता है। पुन: प्रयोज्यता पर विचार करें।
केनन ईके

1
क्यों नहीं obj.GetType के बजाय टाइपोफ़ (T) का उपयोग करें, इस तरह से आपको NullReferenceException नहीं मिलेगी यदि कोई अशक्त संदर्भ प्रकार पास करता है। आप केवल मूल्य प्रकारों को स्वीकार करने के लिए टी पर एक सामान्य बाधा भी डाल सकते हैं। यदि आप ऐसा करते हैं तो निश्चित रूप से आपके पास संकलन समय पर बहुत सारी जानकारी होने लगती है।
ट्रिलियन

objectऔर stringआदिम प्रकार नहीं हैं।
हम सभी मोनिका

@jnylen: यह उत्तर कुछ समय पहले था। मेरा मानना ​​है कि मैंने उस समय प्रतिबिंबित फ्रेमवर्क स्रोत से सोमेथिन को खोदा, लेकिन आज कौन बता सकता है ... निश्चित उत्तर।
केनन ईके

10

ऊपर कुछ बेहतरीन जवाब दिए गए हैं। यहाँ एक समाधान है। विभिन्न परिस्थितियों के लिए तीन अधिभार।

// Extension method, call for any object, eg "if (x.IsNumeric())..."
public static bool IsNumeric(this object x) { return (x==null ? false : IsNumeric(x.GetType())); }

// Method where you know the type of the object
public static bool IsNumeric(Type type) { return IsNumeric(type, Type.GetTypeCode(type)); }

// Method where you know the type and the type code of the object
public static bool IsNumeric(Type type, TypeCode typeCode) { return (typeCode == TypeCode.Decimal || (type.IsPrimitive && typeCode != TypeCode.Object && typeCode != TypeCode.Boolean && typeCode != TypeCode.Char)); }

शून्य चेक जोड़ने पर विचार करें
wiero

वास्तव में अशक्त जांच की आवश्यकता नहीं है - एक विस्तार विधि के रूप में, आप इसे शून्य मान के साथ नहीं कह सकते। बेशक कोई अभी भी एक सामान्य फ़ंक्शन के रूप में कॉल कर सकता है, लेकिन यह एक्सटेंशन पद्धति का अपेक्षित उपयोग नहीं है।
मिक ब्रूनो

5
मुझे लगता है कि कोई इसे शून्य मान के साथ कह सकता है। ऑब्जेक्ट obj = null; obj.IsNumeric ();
वेरो

धन्यवाद वीरो, इसे ठीक कर दिया है। एक अशक्त मूल्य के साथ कॉलिंग एक्सटेंशन पद्धति का एहसास नहीं था, लेकिन निश्चित रूप से यह है!
मिक ब्रूनो

मुझे लगता है कि पहला अधिभार अंत में एक कोष्ठक को याद कर रहा है: "वापसी (x == null; गलत: IsNumeric (x.GetType)));"
ग्लेन गार्सन

8

अपने स्वयं के रोल करने के बजाय, यह बताने के लिए सबसे विश्वसनीय तरीका है कि क्या एक इन-बिल्ट प्रकार संख्यात्मक है, शायद संदर्भ Microsoft.VisualBasicऔर कॉल करने के लिए है Information.IsNumeric(object value)। कार्यान्वयन कई सूक्ष्म मामलों जैसे कि char[]HEX और OCT तार को संभालता है ।


यह सबसे ऊपर होना चाहिए!
नवफाल

4

वहाँ तीन अलग-अलग अवधारणाएँ हैं:

  • अगर यह है जाँच करने के लिए एक नंबर (यानी एक (आमतौर पर बॉक्सिंग) संख्यात्मक मान ही), के साथ प्रकार की जांच is- उदाहरण के लिएif(obj is int) {...}
  • यह जांचने के लिए कि क्या एक स्ट्रिंग को संख्या के रूप में पार्स किया जा सकता है; उपयोगTryParse()
  • लेकिन अगर ऑब्जेक्ट एक नंबर या स्ट्रिंग नहीं है, लेकिन आपको संदेह ToString()है कि ऐसा कुछ दे सकता है जो नंबर की तरह दिखता है , तो उसे कॉल करें ToString() और इसे स्ट्रिंग मानें

पहले दो मामलों में, आपको संभवतः प्रत्येक संख्यात्मक प्रकार को अलग से संभालना होगा जिसे आप ( double/ decimal/ int) का समर्थन करना चाहते हैं - प्रत्येक में अलग-अलग रेंज और सटीकता है, उदाहरण के लिए।

तुम भी एक त्वरित किसी न किसी जाँच के लिए regex को देख सकते हैं।


4

मान लें कि आपका इनपुट एक स्ट्रिंग है ...

2 तरीके हैं:

Double.TryParse () का उपयोग करें

double temp;
bool isNumber = Double.TryParse(input, out temp);

रेगेक्स का उपयोग करें

 bool isNumber = Regex.IsMatch(input,@"-?\d+(\.\d+)?");

4

आप इस तरह कोड का उपयोग कर सकते हैं:

if (n is IConvertible)
  return ((IConvertible) n).ToDouble(CultureInfo.CurrentCulture);
else
  // Cannot be converted.

अपने उद्देश्य एक है Int32, Single, Doubleआदि यह रूपांतरण प्रदर्शन करेंगे। इसके अलावा, एक स्ट्रिंग लागू होता है IConvertibleलेकिन अगर स्ट्रिंग एक डबल करने के लिए परिवर्तनीय नहीं है, तो FormatExceptionफेंक दिया जाएगा।


वास्तव में तारों को पार्स किया जाएगा, लेकिन यदि सही प्रारूप में नहीं है, तो FormatException को फेंक दिया जाता है।
अल्फोकस

@alfoks: आप बिल्कुल सही हैं इसलिए मैंने जवाब अपडेट कर दिया है।
मार्टिन लेवर्स

1

यदि आपकी आवश्यकता वास्तव में है

.ToString () के परिणाम में एक स्ट्रिंग होगी जिसमें अंक और +, -।

और आप double.TryParse का उपयोग करना चाहते हैं तो आपको एक अधिभार पैरामीटर लेने वाले अधिभार का उपयोग करने की आवश्यकता है, और सुनिश्चित करें कि आप इनवेरिएंट संस्कृति का उपयोग कर रहे हैं।

एक संख्या के लिए उदाहरण के लिए जिसमें एक अग्रणी चिन्ह हो सकता है, कोई अग्रणी या अनुगामी व्हाट्सएप नहीं, कोई हजारों विभाजक और एक अवधि दशमलव विभाजक, उपयोग:

NumberStyles style = 
   NumberStyles.AllowLeadingSign | 
   NumberStyles.AllowDecimalPoint | 
double.TryParse(input, style, CultureInfo.InvariantCulture, out result);

1

अपने ही लिखते समय object.IsNumeric()में है कि आप एक मिल जाएगा विस्तार विधि इस सवाल का मैं कोई समस्या में भाग को शाऊल Dolgin के उत्तर के आधार पर OverflowExceptionकरता है, तो आप इसके साथ की कोशिश double.MaxValueयाdouble.MinValue

मेरा "समाधान" नोल्डोरिन से स्वीकृत उत्तर को शाऊल डोलगिन से एक के साथ जोड़ना था और किसी भी चीज़ को पार्स करने की कोशिश करने से पहले एक पैटर्न मिलान स्विच जोड़ना (और थोड़ा सा साफ करने के लिए कुछ सी # 7 अच्छाई का उपयोग करना):

public static bool IsNumeric(this object obj)
{
    if (obj == null) return false;

    switch (obj)
    {
        case sbyte _: return true;
        case byte _: return true;
        case short _: return true;
        case ushort _: return true;
        case int _: return true;
        case uint _: return true;
        case long _: return true;
        case ulong _: return true;
        case float _: return true;
        case double _: return true;
        case decimal _: return true;
    }

    string s = Convert.ToString(obj, CultureInfo.InvariantCulture);

    return double.TryParse(s, NumberStyles.Any, NumberFormatInfo.InvariantInfo, out double _);
}

अशक्त प्रकारों से सावधान रहें।
गिलर्मो प्रांडी

0

हाँ, यह काम करता है:

object x = 1;
Assert.That(x is int);

एक फ्लोटिंग पॉइंट संख्या के लिए आपको फ्लोट प्रकार का उपयोग करके परीक्षण करना होगा:

object x = 1f;
Assert.That(x is float);

यह तब काम करेगा जब वस्तु को किसी वस्तु को निहित या स्पष्ट रूप से डाले जाने से पहले एक int था। आपके उदाहरण में, मैजिक नंबर 1 एक इंट है, और उसके बाद वैरिएबल एक्स के प्रकार में डाली जाती है। यदि आपने ऑब्जेक्ट x = 1.0 किया होता, तो आपका असत्य गलत हो जाता।
डेक्सटर

ऐसी संख्याएं हैं जो इन्टस नहीं हैं।
फ्रेड्रिक मोर्क

हां, तो मेरा कहना है कि मूल रूप से @Noldorin ने अपने उत्तर में अभी क्या है।
पीटर लिलवॉल्ड
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.