स्ट्रिंग को अशक्त प्रकार में बदलें (int, double, etc…)


137

मैं कुछ डेटा रूपांतरण करने का प्रयास कर रहा हूं। दुर्भाग्य से, अधिकांश डेटा स्ट्रिंग्स में है, जहां यह इंट या डबल होना चाहिए, आदि ...

तो मुझे जो मिला है वह कुछ इस तरह है:

double? amount = Convert.ToDouble(strAmount);

इस दृष्टिकोण के साथ समस्या यह है कि strAmount खाली है, अगर यह खाली है तो मैं चाहता हूं कि यह शून्य हो, इसलिए जब मैं इसे डेटाबेस में जोड़ता हूं तो कॉलम शून्य हो जाएगा। इसलिए मैंने यह लिखना समाप्त कर दिया:

double? amount = null;
if(strAmount.Trim().Length>0)
{
    amount = Convert.ToDouble(strAmount);
}

अब यह ठीक काम करता है, लेकिन अब मेरे पास एक के बजाय कोड की पांच लाइनें हैं। इससे चीजें पढ़ना थोड़ा मुश्किल हो जाता है, खासकर जब मेरे पास बड़ी मात्रा में कॉलम हैं।

मैंने सोचा था कि मैं स्ट्रिंग क्लास और जेनेरिक टाइप में पास होने के लिए एक एक्सटेंशन का उपयोग करूंगा, यह इसलिए है क्योंकि यह एक डबल या एक इंट या एक लंबा हो सकता है। इसलिए मैंने यह कोशिश की:

public static class GenericExtension
{
    public static Nullable<T> ConvertToNullable<T>(this string s, T type) where T: struct
    {
        if (s.Trim().Length > 0)
        {
            return (Nullable<T>)s;
        }
        return null;
    }
}

लेकिन मुझे त्रुटि मिलती है: टाइप 'स्ट्रिंग' को 'T' में नहीं बदल सकते?

क्या इसके चारों ओर एक रास्ता है? मैं जेनरिक का उपयोग करने के तरीके बनाने से बहुत परिचित नहीं हूं।


जवाबों:


157

एक और बात का ध्यान रखें कि स्ट्रिंग स्वयं अशक्त हो सकती है।

public static Nullable<T> ToNullable<T>(this string s) where T: struct
{
    Nullable<T> result = new Nullable<T>();
    try
    {
        if (!string.IsNullOrEmpty(s) && s.Trim().Length > 0)
        {
            TypeConverter conv = TypeDescriptor.GetConverter(typeof(T));
            result = (T)conv.ConvertFrom(s);
        }
    }
    catch { } 
    return result;
}

2
आप "टी टाइप" पैरामीटर को छोड़ सकते हैं क्योंकि इसका उपयोग नहीं किया जाता है।
माइकल मीडोज

1
+1, बस मुझे हरा दो। एक छोटी सी नाइट्रिक: परिवर्तित मूल्य को सीधे परिणाम के लिए सौंपा जाना चाहिए, परिणाम के लिए नहीं। यानी, "परिणाम = (टी) दीक्षांत। कॉनवर्टफ्रॉम (ओं);"
ल्यूक

20
यह string.IsNullOrWhiteSpace () के साथ एक सा सरल किया जा सकता है अगर आप .Net4 का उपयोग
Sergej Andrejev

1
@andrefadila - उपयोग करने के लिए: स्ट्रिंग नमूना VendorId = ""; int? sellerId = sampleVendorId.ToNullable <int> ();
मिनर्वा

1
कॉल conv.ConvertFrom टी के एक अशक्त प्रकार को परिवर्तित नहीं करता है, जो इस फ़ंक्शन को थोड़ा काउंटर सहज बनाता है। आप इस समारोह में एक कोशिश पकड़ की जरूरत नहीं है। कोड की ये तीन पंक्तियाँ यह सब बनाती है: अगर (string.IsNullOrWhiteSpace (stringObject)) null वापस आती है; var conv = TypeDescriptor.GetConverter (टाइपोफ़ (टी)); वापसी (टी?) दी गई। कॉनवर्टफ्रॉम (स्ट्रिंगऑब्जेक्ट);
डेविड

54

आप नीचे विस्तार विधि का उपयोग करके देख सकते हैं:

public static T? GetValueOrNull<T>(this string valueAsString)
    where T : struct 
{
    if (string.IsNullOrEmpty(valueAsString))
        return null;
    return (T) Convert.ChangeType(valueAsString, typeof(T));
}

इस तरह से आप यह कर सकते हैं:

double? amount = strAmount.GetValueOrNull<double>();
int? amount = strAmount.GetValueOrNull<int>();
decimal? amount = strAmount.GetValueOrNull<decimal>();

3
IMHO यह समस्या का सबसे सुरुचिपूर्ण समाधान है
Zaffiro

4
वास्तव में .. यह समाधान काम नहीं करता है। changetype nullable प्रकारों में परिवर्तित नहीं होता है। इसके बजाय टाइप करेंइंटरोकेट का उपयोग करें
आरोनएचएस

यही मुझे जानने की आवश्यकता है ... मुझे Convert.ChangeType-Method का उपयोग करते समय अंतर्निहित प्रकार के अशक्त प्रकार का उपयोग करना होगा। क्योंकि यह पैरामीटर रूपांतरण टाइप के लिए एक अशक्त-प्रकार के साथ काम नहीं करता है।
माक्र्स। जूल

27

इस बारे में क्या:


double? amount = string.IsNullOrEmpty(strAmount) ? (double?)null : Convert.ToDouble(strAmount);

बेशक, यह कन्वर्ट फेलिंग को ध्यान में नहीं रखता है।


यदि आप या तो रिटर्न मानों को दोगुना कर देते हैं? (या int ?, आदि), तो यह उन्हें अंतिम डबल में बदलने में सक्षम होगा? ऊपर परिवर्तन देखें।
bdukes

उसके लिए माफ़ करना। कंपाइलर के चीखने तक हमेशा कास्ट को भूल जाएं। :)
जॉन क्राफ्ट

यदि आप शून्य नहीं हैं तो यह विफल हो जाएगा और आप राशि की कोशिश करेंगे। VasValue और var के रूप में राशि की घोषणा करें।
स्टीव

23

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

मैं दर्जनों उत्पादन कार्यक्रमों में लगभग एक साल से इसका उपयोग कर रहा हूं, इसलिए यह बहुत ठोस होना चाहिए।

    public static T To<T>(this IConvertible obj)
    {
        Type t = typeof(T);

        if (t.IsGenericType
            && (t.GetGenericTypeDefinition() == typeof(Nullable<>)))
        {
            if (obj == null)
            {
                return (T)(object)null;
            }
            else
            {
                return (T)Convert.ChangeType(obj, Nullable.GetUnderlyingType(t));
            }
        }
        else
        {
            return (T)Convert.ChangeType(obj, t);
        }
    }

    public static T ToOrDefault<T>
                 (this IConvertible obj)
    {
        try
        {
            return To<T>(obj);
        }
        catch
        {
            return default(T);
        }
    }

    public static bool ToOrDefault<T>
                        (this IConvertible obj,
                         out T newObj)
    {
        try
        {
            newObj = To<T>(obj);
            return true;
        }
        catch
        {
            newObj = default(T);
            return false;
        }
    }

    public static T ToOrOther<T>
                           (this IConvertible obj,
                           T other)
    {
        try
        {
            return To<T>(obj);
        }
        catch
        {
            return other;
        }
    }

    public static bool ToOrOther<T>
                             (this IConvertible obj,
                             out T newObj,
                             T other)
    {
        try
        {
            newObj = To<T>(obj);
            return true;
        }
        catch
        {
            newObj = other;
            return false;
        }
    }

    public static T ToOrNull<T>
                          (this IConvertible obj)
                          where T : class
    {
        try
        {
            return To<T>(obj);
        }
        catch
        {
            return null;
        }
    }

    public static bool ToOrNull<T>
                      (this IConvertible obj,
                      out T newObj)
                      where T : class
    {
        try
        {
            newObj = To<T>(obj);
            return true;
        }
        catch
        {
            newObj = null;
            return false;
        }
    }

2
मुझे नहीं लगता कि सभी रूपांतरण त्रुटियों को अनदेखा करना सही काम है। इसके अलावा, आपको संभवतः सभी प्रकार के अपवादों को नहीं निगलना चाहिए। OutOfMemoryExceptionयदि आप इसे अपवाद प्रकारों के निश्चित सेट तक सीमित नहीं कर सकते, तो कम से कम पुनः फेंक दें।
पॉल ग्रोके

9

आप कोशिश कर सकते हैं:

TypeConverter conv = TypeDescriptor.GetConverter(typeof(int));
conv.ConvertFrom(mystring);

अपनी स्वयं की अशक्त जांच करें और int?यदि आवश्यक हो तो वापस लौटें । आप इसे एक में भी लपेटना चाहेंगेtry {}


6

इसे एक शॉट दें ...

public delegate bool TryParseDelegate<T>(string data, out T output);

public static T? ToNullablePrimitive<T>(this string data, 
    TryParseDelegate<T> func) where T:struct
{
    string.IsNullOrEmpty(data) return null;

    T output;

    if (func(data, out output))
    {
        return (T?)output;
    }

    return null;
}

फिर इसे इस तरह से कॉल करें ...

void doStuff()
{
    string foo = "1.0";

    double? myDouble = foo.ToNullablePrimitive<double>(double.TryParse);

    foo = "1";

    int? myInt = foo.ToNullablePrimitive<int>(int.TryParse);

    foo = "haha";

    int? myInt2 = foo.ToNullablePrimitive<int>(int.TryParse);
}

6

मुझे जोएल का जवाब पसंद है, लेकिन मैंने इसे थोड़ा संशोधित किया है क्योंकि मैं अपवादों को खाने का प्रशंसक नहीं हूं।

    /// <summary>
    /// Converts a string to the specified nullable type.
    /// </summary>
    /// <typeparam name="T">The type to convert to</typeparam>
    /// <param name="s">The string to convert</param>
    /// <returns>The nullable output</returns>
    public static T? ToNullable<T>(this string s) where T : struct
    {
        if (string.IsNullOrWhiteSpace(s))
            return null;

        TypeConverter conv = TypeDescriptor.GetConverter(typeof (T));
        return (T) conv.ConvertFrom(s);
    }

    /// <summary>
    /// Attempts to convert a string to the specified nullable primative.
    /// </summary>
    /// <typeparam name="T">The primitive type to convert to</typeparam>
    /// <param name="data">The string to convert</param>
    /// <param name="output">The nullable output</param>
    /// <returns>
    /// True if conversion is successfull, false otherwise.  Null and whitespace will
    /// be converted to null and return true.
    /// </returns>
    public static bool TryParseNullable<T>(this string data, out T? output) where T : struct
    {
        try
        {
            output = data.ToNullable<T>();
            return true;
        }
        catch
        {
            output = null;
            return false;
        }
    }

5

आप वस्तुओं के साथ निम्नलिखित का उपयोग कर सकते हैं, दुर्भाग्य से यह तार के साथ काम नहीं करता है।

double? amount = (double?)someObject;

मैं किसी प्रॉपर्टी में (बेस पेज पर) सत्र चर लपेटने के लिए इसका उपयोग करता हूं .. इसलिए मेरा वास्तविक उपयोग (मेरे बेस पेज में) है:

public int? OrganisationID
{
    get { return (int?)Session[Constants.Session_Key_OrganisationID]; }
    set { Session[Constants.Session_Key_OrganisationID] = value; }
}

मैं पृष्ठ तर्क में शून्य की जांच करने में सक्षम हूं:

if (base.OrganisationID == null)
    // do stuff

हाय धन्यवाद यह मेरे लिए हल। FYI करें मैं VB.NET का उपयोग कर रहा था, और VB CType(Object, Nullable(Of Double))
इक्विवेलेंट

क्या आपके पहले उदाहरण का एक संस्करण है जिसका उपयोग स्ट्रिंग्स के साथ किया जा सकता है?
4

3

इसके अलावा कोई रास्ता नहीं है। अशक्त, साथ ही आपकी विधि, केवल मान प्रकार का उपयोग करने के लिए विवश है क्योंकि यह तर्क है। स्ट्रिंग एक संदर्भ प्रकार है और इसलिए इस घोषणा के साथ असंगत है।


3
public static class GenericExtension
{
    public static T? ConvertToNullable<T>(this String s) where T : struct 
    {
        try
        {
            return (T?)TypeDescriptor.GetConverter(typeof(T)).ConvertFrom(s);
        }
        catch (Exception)
        {
            return null;
        }
    }
}

3

एक सामान्य समाधान है (किसी भी प्रकार के लिए)। प्रयोज्यता अच्छी है, लेकिन कार्यान्वयन में सुधार किया जाना चाहिए: http://cleansharp.de/wordpress/2011/05/generischer-typeconverter/

यह आपको इस तरह बहुत साफ कोड लिखने की अनुमति देता है:

string value = null;
int? x = value.ConvertOrDefault<int?>();

और भी:

object obj = 1;  

string value = null;
int x = 5;
if (value.TryConvert(out x))
    Console.WriteLine("TryConvert example: " + x); 

bool boolean = "false".ConvertOrDefault<bool>();
bool? nullableBoolean = "".ConvertOrDefault<bool?>();
int integer = obj.ConvertOrDefault<int>();
int negativeInteger = "-12123".ConvertOrDefault<int>();
int? nullableInteger = value.ConvertOrDefault<int?>();
MyEnum enumValue = "SecondValue".ConvertOrDefault<MyEnum>();

MyObjectBase myObject = new MyObjectClassA();
MyObjectClassA myObjectClassA = myObject.ConvertOrDefault<MyObjectClassA>();

जो डाउनवोट कर रहा था कृपया एक टिप्पणी जोड़ें कि इस सार्वभौमिक समाधान में क्या गलत है।
पावेल होडेक

1
खैर, पहले आपके उत्तर में कुछ गड़बड़ है, और वह है "आप अन्य सभी उत्तरों को भूल सकते हैं"। अगर यह सच था (जो ऐसा नहीं है) तो भी गलत होगा। और "सार्वभौमिक समाधान" के साथ क्या गलत है कि यह खराब प्रदर्शन से भरा है ( typeName.IndexOf? वास्तव में?) और गला घोंटने वाला व्यवहार (दिखाया गया TryConvertफ़ंक्शन शून्य मानों को भी सही तरीके से नहीं संभालता है)।
पॉल ग्रोक

3

यहां स्वीकृत उत्तर के आधार पर कुछ है। मैंने यह सुनिश्चित करने के लिए कोशिश / कैच को हटा दिया कि सभी अपवाद निगले नहीं गए हैं और निपटा नहीं गए हैं। यह भी सुनिश्चित किया कि रिटर्न वेरिएबल (स्वीकृत उत्तर में) को कुछ भी नहीं के लिए दो बार आरंभीकृत नहीं किया गया है।

public static Nullable<T> ToNullable<T>(this string s) where T: struct
{
    if (!string.IsNullOrWhiteSpace(s))
    {
        TypeConverter conv = TypeDescriptor.GetConverter(typeof(T));

        return (T)conv.ConvertFrom(s);
    }

    return default(Nullable<T>);
}

2

एनोनिमस प्रकार के लिए मेरा उदाहरण:

private object ConvertNullable(object value, Type nullableType)
{
    Type resultType = typeof(Nullable<>).MakeGenericType(nullableType.GetGenericArguments());
    return Activator.CreateInstance(resultType, Convert.ChangeType(value, nullableType.GetGenericArguments()[0]));
}

...

Type anonimousType = typeof(Nullable<int>);
object nullableInt1 = ConvertNullable("5", anonimousType);
// or evident Type
Nullable<int> nullableInt2 = (Nullable<int>)ConvertNullable("5", typeof(Nullable<int>));

2

एक और बदलाव। यह वाला

  • अपवादों को नहीं निगलता
  • NotSupportedExceptionयदि प्रकार से परिवर्तित नहीं किया जा सकता है तो फेंकता हैstring । उदाहरण के लिए, एक प्रकार कनवर्टर के बिना एक कस्टम संरचना।
  • (T?)nullयदि स्ट्रिंग पार्स करने में विफल रहता है तो अन्यथा वापस आ जाता है। अशक्त या व्हाट्सएप के लिए जाँच करने की आवश्यकता नहीं है।
using System.ComponentModel;

public static Nullable<T> ToNullable<T>(this string s) where T : struct
{
    var ret = new Nullable<T>();
    var conv = TypeDescriptor.GetConverter(typeof(T));

    if (!conv.CanConvertFrom(typeof(string)))
    {
        throw new NotSupportedException();
    }

    if (conv.IsValid(s))
    {
        ret = (T)conv.ConvertFrom(s);
    }

    return ret;
}

1

आइए स्टैक में एक और समान समाधान जोड़ें। यह एक भी enums parses, और यह अच्छा लग रहा है। बहुत सुरक्षित।

/// <summary>
    /// <para>More convenient than using T.TryParse(string, out T). 
    /// Works with primitive types, structs, and enums.
    /// Tries to parse the string to an instance of the type specified.
    /// If the input cannot be parsed, null will be returned.
    /// </para>
    /// <para>
    /// If the value of the caller is null, null will be returned.
    /// So if you have "string s = null;" and then you try "s.ToNullable...",
    /// null will be returned. No null exception will be thrown. 
    /// </para>
    /// <author>Contributed by Taylor Love (Pangamma)</author>
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="p_self"></param>
    /// <returns></returns>
    public static T? ToNullable<T>(this string p_self) where T : struct
    {
        if (!string.IsNullOrEmpty(p_self))
        {
            var converter = System.ComponentModel.TypeDescriptor.GetConverter(typeof(T));
            if (converter.IsValid(p_self)) return (T)converter.ConvertFromString(p_self);
            if (typeof(T).IsEnum) { T t; if (Enum.TryParse<T>(p_self, out t)) return t;}
        }

        return null;
    }

https://github.com/Pangamma/PangammaUtilities-CSharp/blob/master/PangammaUtilities/Extensions/ToNullableStringExtension.cs


0

" जोएल कोएहॉर्न " द्वारा प्रदान किया गया सामान्य उत्तर अच्छा है।

लेकिन, यह उन GetConverter...या try/catchब्लॉकों का उपयोग किए बिना एक और तरीका है ... (मुझे यकीन नहीं है लेकिन यह कुछ मामलों में बेहतर प्रदर्शन हो सकता है):

public static class StrToNumberExtensions
{
    public static short ToShort(this string s, short defaultValue = 0) => short.TryParse(s, out var v) ? v : defaultValue;
    public static int ToInt(this string s, int defaultValue = 0) => int.TryParse(s, out var v) ? v : defaultValue;
    public static long ToLong(this string s, long defaultValue = 0) => long.TryParse(s, out var v) ? v : defaultValue;
    public static decimal ToDecimal(this string s, decimal defaultValue = 0) => decimal.TryParse(s, out var v) ? v : defaultValue;
    public static float ToFloat(this string s, float defaultValue = 0) => float.TryParse(s, out var v) ? v : defaultValue;
    public static double ToDouble(this string s, double defaultValue = 0) => double.TryParse(s, out var v) ? v : defaultValue;

    public static short? ToshortNullable(this string s, short? defaultValue = null) => short.TryParse(s, out var v) ? v : defaultValue;
    public static int? ToIntNullable(this string s, int? defaultValue = null) => int.TryParse(s, out var v) ? v : defaultValue;
    public static long? ToLongNullable(this string s, long? defaultValue = null) => long.TryParse(s, out var v) ? v : defaultValue;
    public static decimal? ToDecimalNullable(this string s, decimal? defaultValue = null) => decimal.TryParse(s, out var v) ? v : defaultValue;
    public static float? ToFloatNullable(this string s, float? defaultValue = null) => float.TryParse(s, out var v) ? v : defaultValue;
    public static double? ToDoubleNullable(this string s, double? defaultValue = null) => double.TryParse(s, out var v) ? v : defaultValue;
}

उपयोग निम्नानुसार है:

var x1 = "123".ToInt(); //123
var x2 = "abc".ToInt(); //0
var x3 = "abc".ToIntNullable(); // (int?)null 
int x4 = ((string)null).ToInt(-1); // -1
int x5 = "abc".ToInt(-1); // -1

var y = "19.50".ToDecimal(); //19.50

var z1 = "invalid number string".ToDoubleNullable(); // (double?)null
var z2 = "invalid number string".ToDoubleNullable(0); // (double?)0

@MassimilianoKraus हो सकता है, लेकिन यह एक सरल 12 लाइनों वाला कोड है, जिसे एक बार लिखा जाता है, लेकिन सभी समय का उपयोग करते हुए। और, जैसा कि मैंने कहा, यह उन TypeDescriptor.GetConverter... कोड का उपयोग करने की तुलना में तेज होना चाहिए । यह सिर्फ एक और तरीका है।
एस.परपोशन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.