سؤال

أرغب في تحليل سلسلة إلى قيمة لاغية في C#.أي.أريد استعادة القيمة int للسلسلة أو القيمة الخالية إذا تعذر تحليلها.

كنت آمل نوعًا ما أن ينجح هذا

int? val = stringVal as int?;

لكن هذا لن ينجح، لذا فإن الطريقة التي أفعل بها الآن هي أنني كتبت طريقة التمديد هذه

public static int? ParseNullableInt(this string value)
{
    if (value == null || value.Trim() == string.Empty)
    {
        return null;
    }
    else
    {
        try
        {
            return int.Parse(value);
        }
        catch
        {
            return null;
        }
    }
}   

هل هناك طريقة أفضل للقيام بذلك؟

يحرر: شكرًا لاقتراحات TryParse، كنت أعرف ذلك، لكن الأمر كان بنفس الطريقة.أنا مهتم أكثر بمعرفة ما إذا كانت هناك طريقة إطار عمل مضمنة سيتم تحليلها مباشرة إلى قيمة لاغية؟

هل كانت مفيدة؟

المحلول

int.TryParse ربما يكون الأمر أسهل قليلاً:

public static int? ToNullableInt(this string s)
{
    int i;
    if (int.TryParse(s, out i)) return i;
    return null;
}

يحرر @ جلين int.TryParse "مدمج في الإطار".هذا و int.Parse نكون ال طريقة لتحليل السلاسل إلى ints.

نصائح أخرى

يمكنك القيام بذلك في سطر واحد، باستخدام العامل الشرطي وحقيقة أنه يمكنك الإرسال null إلى نوع لاغٍ (سطرين، إذا لم يكن لديك int موجود مسبقًا، فيمكنك إعادة استخدامه لإخراج TryParse):

ما قبل C#7:

int tempVal;
int? val = Int32.TryParse(stringVal, out tempVal) ? Int32.Parse(stringVal) : (int?)null;

مع بناء جملة C#7 المحدث الذي يسمح لك بإعلان متغير الإخراج في استدعاء الأسلوب، يصبح هذا الأمر أكثر بساطة.

int? val = Int32.TryParse(stringVal, out var tempVal) ? tempVal : (int?)null;

لقد واجهت هذه المشكلة وانتهى بي الأمر بهذا (بعد كل شيء، ملف if و 2 returnلقد طال أمده!):

int? ParseNInt (string val)
{
    int i;
    return int.TryParse (val, out i) ? (int?) i : null;
}

وعلى صعيد أكثر جدية، حاول عدم الاختلاط int, ، وهي كلمة أساسية في C#، مع Int32, ، وهو نوع .NET Framework BCL - على الرغم من أنه يعمل، إلا أنه يجعل التعليمات البرمجية تبدو فوضوية.

جلين سلافين:أنا مهتم أكثر بمعرفة ما إذا كانت هناك طريقة إطار مدمجة ستتحلى مباشرة في int لاغية؟

يوجد هذا الأسلوب الذي سيتم تحليله مباشرة إلى قيمة int لاغية (وليس فقط int) إذا كانت القيمة صالحة مثل سلسلة فارغة أو فارغة، ولكنها تطرح استثناءً للقيم غير الصالحة لذا ستحتاج إلى التقاط الاستثناء وإرجاع القيمة الافتراضية لتلك الحالات:

public static T Parse<T>(object value)
{
    try { return (T)System.ComponentModel.TypeDescriptor.GetConverter(typeof(T)).ConvertFrom(value.ToString()); }
    catch { return default(T); }
}

لا يزال من الممكن استخدام هذا الأسلوب للتوزيعات غير الفارغة وكذلك التي لاغية:

enum Fruit { Orange, Apple }
var res1 = Parse<Fruit>("Apple");
var res2 = Parse<Fruit?>("Banana");
var res3 = Parse<int?>("100") ?? 5; //use this for non-zero default
var res4 = Parse<Unit>("45%");

ملحوظة: توجد طريقة IsValid على المحول يمكنك استخدامها بدلاً من التقاط الاستثناء (تؤدي الاستثناءات المطروحة إلى النفقات العامة غير الضرورية إذا كان متوقعا).لسوء الحظ، فهو يعمل فقط منذ .NET 4 ولكن لا تزال هناك مشكلة حيث لا يتحقق من إعداداتك المحلية عند التحقق من صحة تنسيقات DateTime الصحيحة، راجع الخطأ 93559.

جرب هذا:

public static int? ParseNullableInt(this string value)
{
    int intValue;
    if (int.TryParse(value, out intValue))
        return intValue;
    return null;
}

موضوع قديم ولكن ماذا عن:

public static int? ParseToNullableInt(this string value)
{
     return String.IsNullOrEmpty(value) ? null : (int.Parse(value) as int?);
}

يعجبني هذا بشكل أفضل باعتباره طلبًا لتحليل القيمة الخالية، لن يؤدي إصدار TryParse إلى حدوث خطأ على سبيل المثال.ToNullableInt32(XXX).قد يؤدي ذلك إلى حدوث أخطاء صامتة غير مرغوب فيها.

أشعر أن الحل الخاص بي هو حل نظيف وجميل جدًا:

public static T? NullableParse<T>(string s) where T : struct
{
    try
    {
        return (T)typeof(T).GetMethod("Parse", new[] {typeof(string)}).Invoke(null, new[] { s });
    }
    catch (Exception)
    {
        return null;
    }
}

هذا بالطبع حل عام يتطلب فقط أن يكون للوسيطة العامة طريقة ثابتة "Parse(string)".يعمل هذا مع الأرقام والقيمة المنطقية والتاريخ والوقت وما إلى ذلك.

var result = int.TryParse(foo, out var f) ? f : default(int?);

مصادر:

يمكنك نسيان جميع الإجابات الأخرى - هناك حل عام رائع:http://cleansharp.de/wordpress/2011/05/generischer-typeconverter/

يتيح لك ذلك كتابة تعليمات برمجية نظيفة جدًا مثل هذا:

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

و أيضا:

object obj = 1;  

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

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

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

يجب أن يعمل ما يلي لأي نوع بنية.يعتمد على الكود بواسطة مات مانيلا من منتديات MSDN.وكما يشير مورف، فإن معالجة الاستثناءات قد تكون باهظة الثمن مقارنة باستخدام طريقة TryParse المخصصة للأنواع.

        public static bool TryParseStruct<T>(this string value, out Nullable<T> result)
            where T: struct 
        {
            if (string.IsNullOrEmpty(value))
            {
                result = new Nullable<T>();

                return true;
            }

            result = default(T);
            try
            {
                IConvertible convertibleString = (IConvertible)value;
                result = new Nullable<T>((T)convertibleString.ToType(typeof(T), System.Globalization.CultureInfo.CurrentCulture));
            }
            catch(InvalidCastException)
            {
                return false;
            }
            catch (FormatException)
            {
                return false;
            }

           return true;
        }

كانت هذه حالات الاختبار الأساسية التي استخدمتها.

        string parseOne = "1";
        int? resultOne;
        bool successOne = parseOne.TryParseStruct<int>(out resultOne);
        Assert.IsTrue(successOne);
        Assert.AreEqual(1, resultOne);

        string parseEmpty = string.Empty;
        int? resultEmpty;
        bool successEmpty = parseEmpty.TryParseStruct<int>(out resultEmpty);
        Assert.IsTrue(successEmpty);
        Assert.IsFalse(resultEmpty.HasValue);

        string parseNull = null;
        int? resultNull;
        bool successNull = parseNull.TryParseStruct<int>(out resultNull);
        Assert.IsTrue(successNull);
        Assert.IsFalse(resultNull.HasValue);

        string parseInvalid = "FooBar";
        int? resultInvalid;
        bool successInvalid = parseInvalid.TryParseStruct<int>(out resultInvalid);
        Assert.IsFalse(successInvalid);

أود أن أقترح اتباع طرق التمديد لتحليل السلسلة إلى قيمة int مع القدرة على تحديد القيمة الافتراضية في حالة عدم إمكانية التحليل:

public static int ParseInt(this string value, int defaultIntValue = 0)
        {
            return int.TryParse(value, out var parsedInt) ? parsedInt : defaultIntValue;
        }

public static int? ParseNullableInt(this string value)
        {
            if (string.IsNullOrEmpty(value))
                return null;

            return value.ParseInt();
        }

هذا الحل عام بدون انعكاس.

public static Nullable<T> ParseNullable<T>(string s, Func<string, T> parser) where T : struct
{
    if (string.IsNullOrEmpty(s) || string.IsNullOrEmpty(s.Trim())) return null;
    else return parser(s);
}

static void Main(string[] args)
{
    Nullable<int> i = ParseNullable("-1", int.Parse);
    Nullable<float> dt = ParseNullable("3.14", float.Parse);
}

أنا مهتم أكثر بمعرفة ما إذا كانت هناك طريقة إطار عمل مدمجة يمكن تحليلها مباشرة إلى قيمة لاغية؟

لا يوجد.

شعرت أنني يجب أن أشارك ما لدي وهو أكثر عمومية قليلاً.

الاستخدام:

var result = "123".ParseBy(int.Parse);

var result2 = "123".ParseBy<int>(int.TryParse);

حل:

public static class NullableParse
{
    public static Nullable<T> ParseBy<T>(this string input, Func<string, T> parser)
        where T : struct
    {
        try
        {
            return parser(input);
        }
        catch (Exception exc)
        {
            return null;
        }
    }

    public delegate bool TryParseDelegate<T>(string input, out T result);

    public static Nullable<T> ParseBy<T>(this string input, TryParseDelegate<T> parser)
        where T : struct
    {
        T t;
        if (parser(input, out t)) return t;
        return null;
    }
}

الإصدار الأول أبطأ لأنه يتطلب تجربة ولكنه يبدو أكثر نظافة.إذا لم يتم استدعاؤها عدة مرات باستخدام سلاسل غير صالحة، فهذا ليس مهمًا.إذا كان الأداء يمثل مشكلة، فيرجى ملاحظة أنه عند استخدام أساليب TryParse، فإنك تحتاج إلى تحديد معلمة النوع لـ ParseBy حيث لا يمكن للمترجم استنتاجها.اضطررت أيضًا إلى تحديد المفوض لأنه لا يمكن استخدام الكلمة الأساسية out داخل Func<>، ولكن على الأقل لا يتطلب المترجم هذه المرة مثيلًا صريحًا.

وأخيرًا، يمكنك استخدامه مع بنيات أخرى أيضًا، على سبيل المثال.العشري، التاريخ والوقت، الدليل، الخ.

لقد وجدت وقمت بتعديل بعض التعليمات البرمجية لفئة NullableParser العامة.الكود الكامل موجود على مدونتي محاولة تحليل لاغية

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Globalization;
namespace SomeNamespace
{
    /// <summary>
    /// A parser for nullable types. Will return null when parsing fails.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    ///
    public static class NullableParser<T> where T : struct
    {
        public delegate bool TryParseDelegate(string s, out T result);
        /// <summary>
        /// A generic Nullable Parser. Supports parsing of all types that implements the tryParse method;
        /// </summary>
        /// <param name="text">Text to be parsed</param>
        /// <param name="result">Value is true for parse succeeded</param>
        /// <returns>bool</returns>
        public static bool TryParse(string s, out Nullable<T> result)
        {
            bool success = false;
            try
            {
                if (string.IsNullOrEmpty(s))
                {
                    result = null;
                    success = true;
                }
                else
                {
                    IConvertible convertableString = s as IConvertible;
                    if (convertableString != null)
                    {
                        result = new Nullable<T>((T)convertableString.ToType(typeof(T),
                            CultureInfo.CurrentCulture));
                        success = true;
                    }
                    else
                    {
                        success = false;
                        result = null;
                    }
                }
            }
            catch
            {
                success = false;
                result = null;
            }
            return success;
        }
    }
}
    public static void Main(string[] args)
    {

        var myString = "abc";

        int? myInt = ParseOnlyInt(myString);
        // null

        myString = "1234";

        myInt = ParseOnlyInt(myString);
        // 1234
    }
    private static int? ParseOnlyInt(string s)
    {
        return int.TryParse(s, out var i) ? i : (int?)null;
    }

يجب أبداً استخدم استثناءً إذا لم تكن مضطرًا إلى ذلك - فالنفقات العامة مروعة.

تعمل الاختلافات في TryParse على حل المشكلة - إذا كنت ترغب في الإبداع (لجعل التعليمات البرمجية الخاصة بك تبدو أكثر أناقة) فمن المحتمل أن تفعل شيئًا باستخدام طريقة الامتداد في 3.5 ولكن الرمز سيكون هو نفسه تقريبًا.

باستخدام المفوضين، تكون التعليمة البرمجية التالية قادرة على توفير إمكانية إعادة الاستخدام إذا وجدت نفسك بحاجة إلى التحليل الفارغ لأكثر من نوع بنية واحد.لقد عرضت كلا الإصدارين .Parse() و .TryParse() هنا.

وهذا مثال للاستخدام:

NullableParser.TryParseInt(ViewState["Id"] as string);

وهنا هو الرمز الذي يوصلك إلى هناك ...

public class NullableParser
  {
    public delegate T ParseDelegate<T>(string input) where T : struct;
    public delegate bool TryParseDelegate<T>(string input, out T outtie) where T : struct;
    private static T? Parse<T>(string input, ParseDelegate<T> DelegateTheParse) where T : struct
    {
      if (string.IsNullOrEmpty(input)) return null;
      return DelegateTheParse(input);
    }
    private static T? TryParse<T>(string input, TryParseDelegate<T> DelegateTheTryParse) where T : struct
    {
      T x;
      if (DelegateTheTryParse(input, out x)) return x;
      return null;
    }
    public static int? ParseInt(string input)
    {
      return Parse<int>(input, new ParseDelegate<int>(int.Parse));
    }
    public static int? TryParseInt(string input)
    {
      return TryParse<int>(input, new TryParseDelegate<int>(int.TryParse));
    }
    public static bool? TryParseBool(string input)
    {
      return TryParse<bool>(input, new TryParseDelegate<bool>(bool.TryParse));
    }
    public static DateTime? TryParseDateTime(string input)
    {
      return TryParse<DateTime>(input, new TryParseDelegate<DateTime>(DateTime.TryParse));
    }
  }

لقد توصلت إلى هذه الطريقة، والتي استوفت متطلباتي (أردت أن تحاكي طريقة الامتداد الخاصة بي قدر الإمكان عودة TryParse لإطار العمل، ولكن بدون كتل محاولة{} Catch{} ودون أن يشكو المترجم من استنتاج نوع لاغٍ ضمن طريقة الإطار)

private static bool TryParseNullableInt(this string s, out int? result)
{
    int i;
    result = int.TryParse(s, out i) ? (int?)i : null;
    return result != null;
}

أقترح رمز رفع الصوت عاليا.يمكنك العمل مع استثناء، عند حدوث خطأ في التحويل.

public static class Utils {      
public static bool TryParse<Tin, Tout>(this Tin obj, Func<Tin, Tout> onConvert, Action<Tout> onFill, Action<Exception> onError) {
  Tout value = default(Tout);
  bool ret = true;
  try {
    value = onConvert(obj);
  }
  catch (Exception exc) {
    onError(exc);
    ret = false;
  }
  if (ret)
    onFill(value);
  return ret;
}

public static bool TryParse(this string str, Action<int?> onFill, Action<Exception> onError) {
  return Utils.TryParse(str
    , s => string.IsNullOrEmpty(s) ? null : (int?)int.Parse(s)
    , onFill
    , onError);
}
public static bool TryParse(this string str, Action<int> onFill, Action<Exception> onError) {
  return Utils.TryParse(str
    , s => int.Parse(s)
    , onFill
    , onError);
}
}

استخدم طريقة الامتداد هذه في الكود (املأ int؟خاصية العمر لفئة الشخص):

string ageStr = AgeTextBox.Text;
Utils.TryParse(ageStr, i => person.Age = i, exc => { MessageBox.Show(exc.Message); });

أو

AgeTextBox.Text.TryParse(i => person.Age = i, exc => { MessageBox.Show(exc.Message); });

أدرك أن هذا موضوع قديم، لكن ألا يمكنك ببساطة:

(Nullable<int>)int.Parse(stringVal);

?

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top