Bir dizgiyi boş bir int olarak ayrıştırma


300

Bir dize C # nullable int içine ayrıştırmak istiyorum. yani. Ayrıştırılamazsa dize int değerini veya null geri almak istiyorum.

Bunun işe yarayacağını umuyordum

int? val = stringVal as int?;

Ama bu işe yaramayacak, bu yüzden şimdi bunu yapmamın yolu bu uzantı yöntemini

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;
        }
    }
}   

Bunu yapmanın daha iyi bir yolu var mı?

EDIT: TryParse önerileri için teşekkürler, bunu biliyordum, ama aynı işe yaradı. Ben doğrudan bir boş int içine ayrıştırılacak yerleşik bir çerçeve yöntemi olup olmadığını bilmek ilgileniyorum?


1
İf satırını daha net hale getirmek için string.IsNullOrEmpty (value) öğesini kullanabilirsiniz.
Özgür Kaplan

Jenerik dönüşümünü kullanmayı düşünün stackoverflow.com/questions/773078/…
Michael Freidgeim

Yanıtlar:


352

int.TryParse muhtemelen biraz daha kolay:

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

Edit @Glenn int.TryParse"çerçeve içine inşa edilmiştir". Bu ve int.Parseolan ints için dizeleri ayrıştırmak yol.


82
bir daha az satır: dönüş Int32.TryParse (s, out i)? i: boş;
Chris,

2
"a" null döndürür, ancak int değildir ve istisna
atmalıdır

54
@Chris, derleyici satır içi if ifadenizi beğenmez (Bu türler uyumlu değildir: 'int': 'null'). Bunu değiştirmek zorundayım: dönüş Int32.TryParse (s, dışarı i)? (int?) i: boş;
death_au

8
Int32 sadece int için bir takma addır. İnt.TryParse kullanacağım türleri hizalamak için kullanılır. İnt (farklı bir bit uzunluğu tamsayısını temsil etmek için kullanılırsa / ne zaman kullanılırsa), Int32 int ile hizalanmaz.
Richard Collette

4
dönüş int.Parse (s, out i)? (int?) i: boş;
Nick Spreitzer

177

Koşullu operatörü ve nullsıfırlanabilir bir türe yayınlayabileceğiniz gerçeğini kullanarak bir satırda yapabilirsiniz (iki satır, önceden varolan bir int'iniz yoksa çıktısı için yeniden kullanabilirsiniz TryParse):

Ön C # 7:

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

C # 7'nin yöntem çağrısında bir çıktı değişkeni bildirmenizi sağlayan güncellenmiş sözdizimi ile bu daha da basitleşir.

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

4
Bu, koşullu operatör hakkındaki görüşünüze bağlı olduğunu düşünüyorum. Zihinsel modelim if-else eşdeğeri için hemen hemen sözdizimsel şeker olması, bu durumda versiyonum ve Matt'lerim daha açık olduğu için benim daha fazla cmopaktı var.
McKenzieG1

11
Burada değerlendirme sırası yan etkisi yoktur. Tüm adımlar açıkça sıralanmıştır ve doğrudur.
Jon Hanna

22
dönüşint.TryParse(val, out i) ? i : default(int?);
Bart Calixto

7
@ Bart'ın "cevabı" burada en iyisi!
Andre Figueiredo

4
Ve şimdi C # 6'da, bir satır olabilir! Int32.TryParse (stringVal, out var tempVal)? tempVal: (int?) null;
MerickOWA

34

[ @ Sblom'un önerisine göre modern C # kullanmak için güncellendi ]

Bu sorunu vardı ve ben ile sonuçlandı (sonuçta, bir ifve 2 returns soo uzun soluklu!):

int? ToNullableInt (string val)
    => int.TryParse (val, out var i) ? (int?) i : null;

Daha ciddi bir notta, bir .NET Framework BCL türü olan intbir C # anahtar kelimesi olan karıştırmamaya çalışın Int32- çalışmasına rağmen, kod dağınık görünmesini sağlar.


3
Bunun aslında bir kez derlendiğinde daha iyi performans gösteren bir şeye dönüşeceğinden emin değilim
BuZz

1
C # 7'de daha da özlü: int i;satırı sil ve sadece gitreturn int.TryParse (val, out var i) ? (int?) i : null;
sblom

2
Yani bütünlük için ;-)int? ParseNInt (string val) => int.TryParse (val, out var i) ? (int?) i : null;
Duckboy

C # 6 ile bu 1 satıra indirgenebilir: return int.TryParse (değer, çıkış var sonuç)? sonuç: (int?) null;
MeanGreen

16

Glenn Slaven : Doğrudan boş bir int'e ayrıştırılacak yerleşik bir çerçeve yöntemi olup olmadığını bilmekle ilgileniyorum.

Değer null veya boş dize gibi geçerliyse, ancak geçersiz değerler için bir istisna atar, bu nedenle özel durumu yakalamanız ve varsayılan değeri döndürmeniz gerekir. bu durumlar için:

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

Bu yaklaşım, null edilemeyen ayrıştırmaların yanı sıra nullable'ları için de kullanılabilir:

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%");

Not: Dönüştürücünün istisnayı yakalamak yerine kullanabileceğiniz bir IsValid yöntemi vardır (istisnalar atıldığında beklenmedik ek yüke neden olur). Ne yazık ki sadece .NET 4'ten beri çalışıyor, ancak hala doğru DateTime formatlarını doğrularken yerel ayarınızı kontrol etmediği bir sorun var, bkz. Hata 93559 .


Bu tamsayılar için test ve int.TryParse ((dize) değeri, var sonuç) çok daha yavaş? sonuç: varsayılan (int?);
Wouter

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

Kaynaklar:


bu nasıl olabilir? Tryparse çalışmaz veya null değişkenler ve örneğinizdeki f null değer olmalıdır.
John Lord

Ne demek istediğinizi açıklayabilir misiniz @JohnLord
Jaa H

tryparse null değerine sahip olmayan bir değişkene konulmasını bekliyor, bu nedenle varsayılan (int?) kuvveti var null değer olmaz mı?
John Lord

@JohnLord belki bu ne olup bittiğini anlamanıza yardımcı olacaktır stackoverflow.com/questions/3632918/…
Jaa H

9

Eski konu, ama nasıl?

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

Ben null ayrıştırmak için gerekli requriement, TryParse sürümü örneğin ToNullableInt32 (XXX) bir hata atmak olmaz gibi bu daha iyi. Bu istenmeyen sessiz hatalara neden olabilir.


1
Bu tam olarak nokta - dize ayrıştırılamıyorsa int, nullbir istisna atmamalı, geri dönmelidir .
Mart'ta

1
değer sayısal değilse, int.Parse, null döndürmeyle aynı olmayan bir istisna atar.
bir phu

8

Bunu dene:

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

5

Çözümümün çok temiz ve güzel bir çözüm olduğunu hissediyorum:

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;
    }
}

Bu elbette sadece jenerikler bağımsız değişkeninin statik bir yöntemi "Ayrıştırma (dize)" gerektiren genel bir çözümdür. Bu sayılar, boole, DateTime vb. İçin çalışır.


5

Diğer tüm cevapları unutabilirsiniz - harika bir genel çözüm var: http://cleansharp.de/wordpress/2011/05/generischer-typeconverter/

Bu, şöyle çok temiz bir kod yazmanıza izin verir:

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

ve ayrıca:

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();

1
Bu gerçekten çok faydalı. Bence bu standart c # kütüphanelerinde olmalı çünkü dönüşümler her programda çok yaygındır;)
BigChief

Bu çok güzel ve kullanışlı, AMA geniş bir ürün koleksiyonunda her öğe için dönüşüm yapmanız gerektiğinde son derece yavaş olduğunu ekleyebilirim. 20000 öğe ile test ettim: Bu yaklaşımı kullanarak, her bir öğenin 8 özelliğini dönüştürmek tüm koleksiyonu bitirmek için 1 saat kadar sürer. Aynı örnek verilerle ancak Matt Hamilton'un yaklaşımını kullanarak tamamlanması sadece birkaç saniye sürer.
zed

3

Herhangi bir yapı türü için aşağıdakiler çalışmalıdır. MSDN forumlarından Matt Manela'nın koduna dayanmaktadır . Murph'un işaret ettiği gibi, istisna işleme Türleri özel TryParse yöntemini kullanmaya kıyasla pahalı olabilir.

        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;
        }

Bunlar kullandığım temel test vakalarıydı.

        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);

3

Ben ayrıştırma mümkün değilse varsayılan değer tanımlama yeteneği ile int değerine dizeyi ayrıştırma için aşağıdaki uzantı yöntemleri öneriyoruz:

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();
        }

Zaten çok fazla ve hatta yüksek oylanmış cevaplar var. Cevabınızın gerçekten gerekli olduğunu ve bu yayına yeni bir kalite eklediğini düşünüyor musunuz?
L. Guthardt

1
@ L.Guthardt Evet, sanırım. Sanırım cevabım sorunu çözmek için daha evrensel bir yol getiriyor söz konusu anlatıyor. Teşekkür ederim.
Aleksandr Neizvestnyi

2

Bu çözüm yansıma yükü olmadan jeneriktir.

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);
}

Ben değiştirmek düşünüyorum IsNullOrEmptyileIsNullOrWhitespace
NibblyPig


1

Biraz daha genel olan benimkini paylaşmam gerektiğini hissettim.

Kullanımı:

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

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

Çözüm:

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;
    }
}

İlk sürüm daha yavaştır çünkü bir try-catch gerektirir, ancak daha temiz görünür. Geçersiz dizelerle birçok kez çağrılmazsa, o kadar önemli değildir. Performans bir sorunsa, TryParse yöntemlerini kullanırken, derleyici tarafından çıkarılamadığından ParseBy'nin type parametresini belirtmeniz gerektiğini lütfen unutmayın. Ben de bir temsilci out out anahtar kelime Func <> içinde kullanılamaz olarak tanımlamak zorunda kaldı, ama en azından bu kez derleyici açık bir örnek gerektirmez.

Son olarak, ondalık, DateTime, Guid vb.Gibi diğer yapılarla da kullanabilirsiniz.


1

Buldum ve bir Generic NullableParser sınıfı için bazı kod adapte. Tam kod blogumda Nullable TryParse

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;
        }
    }
}

1
404 Bulunamadı. sadece bir link vermek için iyi bir uygulama değil
Kirli-akış

üzgünüm @ @ tam kod ile kirli-akış güncelleme. Hiç olmadığı kadar iyi geç :)
John Dauphine

1
    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;
    }

1
myString sayısal değilse, int.Parse, null döndürmeyle aynı olmayan bir istisna atar.
bir phu

0

Gerekmiyorsa asla istisna kullanmamalısınız - ek yük korkunçtur.

TryParse'deki varyasyonlar sorunu çözer - yaratıcı olmak istiyorsanız (kodunuzu daha zarif hale getirmek için) muhtemelen 3.5'te bir uzantı yöntemiyle bir şeyler yapabilirsiniz, ancak kod aşağı yukarı aynı olacaktır.


0

Temsilcileri kullanarak, aşağıdaki kod, birden çok yapı türü için boş değer ayrıştırmaya ihtiyaç duyduğunuzda yeniden kullanılabilirlik sağlayabilir. Burada hem .Parse () hem de .TryParse () sürümlerini gösterdim.

Bu örnek bir kullanımdır:

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

Ve işte sizi oraya götüren kod ...

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));
    }
  }

0

Bunun eski bir konu olduğunun farkındayım, ama basitçe yapamazsınız:

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

?


Ancak, stringVal yanlış biçimde ise bir istisna alırsınız. Int.Parse belgelerine bakın
Alex

0

Gereksinimlerimi karşılayan bu ile geldim (Uzatma yöntemimin çerçevenin TryParse dönüşünü olabildiğince yakın taklit etmesini istedim, ancak {} catch {} bloklarını denemeden ve derleyici bir çıkarımdan şikayet etmeden çerçeve yöntemindeki boş değer türü)

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

0

Aşağıdaki kodu öneririm. Dönüştürme hatası oluştuğunda istisna ile çalışabilirsiniz.

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);
}
}

Kodda şu uzantı yöntemini kullanın (bir kişi sınıfının int? Yaş özelliğini doldurun):

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

VEYA

AgeTextBox.Text.TryParse(i => person.Age = i, exc => { MessageBox.Show(exc.Message); });
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.