文字列をnull許容のintに解析する方法


300

文字列をC#でnull許容のintに解析したいのですが。すなわち。文字列のint値、または解析できない場合はnullを取得したい。

これがうまくいくことを期待していた

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の提案をありがとう、私はそれについて知っていましたが、同じようにうまくいきました。null可能なintに直接解析する組み込みのフレームワークメソッドがあるかどうかを知ることに、もっと興味がありますか?


1
string.IsNullOrEmpty(value)を使用して、if行をより明確にすることができます。
Özgürカプラン

ジェネリック医薬品の変換に使用することを検討stackoverflow.com/questions/773078/...を
マイケルFreidgeim

回答:


352

int.TryParse おそらく少し簡単です:

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

Edit @Glenn int.TryParseは「フレームワークに組み込まれています」。これint.Parse文字列をintに解析する方法です。


82
1行少ない:Int32.TryParse(s、out i)を返しますか?i:null;
クリスシャウト、

2
"a"はnullを返しますが、それはintではなく、例外をスローする必要があります
Arsen Mkrtchyan

54
@Chris、コンパイラーはインラインifステートメントを好きではありません(これらのタイプには互換性がありません: 'int': 'null')。私はそれを修正しなければなりませんでした:return Int32.TryParse(s、out i)?(int?)i:null;
death_au 2012年

8
Int32は単にintのエイリアスです。私はint.TryParseを使用して、整列で使用されている型を維持します。(発生した)異なるビット長の整数を表すためにintが使用されている場合、Int32はintと整列しません。
Richard Collette

4
int.TryParse(s、out i)を返しますか?(int?)i:null;
Nick Spreitzer、2015

178

条件演算子とnullnull許容型にキャストできるという事実を使用して、これを1行で実行できます(既存のintがない場合は2行で、の出力に再利用できます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;

4
それは、条件演算子の見方次第だと思います。私のメンタルモデルは、if-elseと同等の構文上の砂糖であることです。その場合、私のバージョンとMattはほぼ同じであり、彼はより明示的で、よりcmopactをマイニングしています。
McKenzieG1 2010年

11
ここには、評価順序の副作用はありません。すべてのステップは明示的に順序付けられ、正しいものです。
Jon Hanna

22
リターンint.TryParse(val, out i) ? i : default(int?);
Bart Calixto

7
@バートの「答え」はここが一番です!
Andre Figueiredo

4
そして今、C#6では、1行にすることができます!Int32.TryParse(stringVal、out var tempVal)?tempVal:(int?)null;
MerickOWA 2014年

34

[ @sblomの提案に従って最新のC#を使用するように更新 ]

私はこの問題を抱えていて、これで終わりました(結局のところ、if2 return秒は非常に長い時間です!):

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

より深刻な注意点としてint、C#キーワードであるとInt32.NET Framework BCLタイプであるを混在させないようにしてください。


3
これが実際にコンパイルされるとパフォーマンスが向上するものになるかどうかは
わかり

1
C#7でさらに簡潔にする:int i;行を削除してreturn int.TryParse (val, out var i) ? (int?) i : null;
そのまま続行

2
したがって、完全をint? ParseNInt (string val) => int.TryParse (val, out var i) ? (int?) i : null;
期す

C#6では、これを1行に減らすことができます:return int.TryParse(value、out var result)?結果:(int?)null;
MeanGreen 2018年

16

Glenn Slaven:私は、null許容のintに直接解析する組み込みのフレームワークメソッドがあるかどうかを知りたいと思っていますか?

値がnullまたは空の文字列のように有効な場合、null可能な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); }
}

このアプローチは、null可能でない解析だけでなくnull可能でも使用できます。

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を参照してください。


私はこれを整数でテストしましたが、int.TryParse((string)value、out var result)よりもはるかに遅いですか?結果:default(int?);
はWouter

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

出典:


これはどのように機能しますか?Tryparseが機能しないか、変数をnullにできるため、この例のfはnullにできる必要があります。
John Lord

@JohnLordの意味を明確にしてください
Jaa H

tryparseはnull可能ではない変数に入れられることを期待しているので、あなたのdefault(int?)はvarをnull可能にしないでしょうか?
John Lord

@JohnLord多分これは、stackoverflow.com
Jaa H

9

古いトピックですが、どうですか:

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

nullを解析する場所の要件として、TryParseバージョンはToNullableInt32(XXX)などでエラーをスローしないので、私はこれがより好きです。これにより、不要なサイレントエラーが発生する可能性があります。


1
これがまさにポイントです。文字列を解析できない場合は、例外をスローするのではなく、intを返す必要がnullあります。
スビック

1
値が数値でない場合、int.Parseは例外をスローしますが、これはnullを返すこととは異なります。
2016年

8

これを試して:

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

5

私の解決策は非常にクリーンで素晴らしい解決策だと感じています:

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)」を持つことのみを必要とするジェネリックソリューションです。これは、数値、ブール値、DateTimeなどで機能します。


5

あなたは他のすべての答えを忘れることができます-素晴らしい一般的な解決策があります: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();

1
これは確かに非常に便利です。私の意見では、変換はすべてのプログラムで非常に一般的であるため、これは標準のc#ライブラリにあるはずです;)
BigChief 2013

これは非常に便利で便利ですが、アイテムの大規模なコレクションの各要素を変換する必要がある場合は、非常に遅くなることを付け加えておきます。私は20000項目でテストしました。このアプローチを使用すると、各項目の8つのプロパティを変換すると、コレクション全体が完了するまでに最大1時間かかります。同じサンプルデータですが、Matt Hamiltonのアプローチを使用すると、完了するまでに数秒しかかかりません。
ZED

3

以下は、すべての構造体タイプで機能します。これは、MSDNフォーラムのMatt Manelaによるコードに基づいています。Murphが指摘するように、例外処理は、Types専用の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);

3

解析ができない場合にデフォルト値を定義する機能を備えた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();
        }

すでに非常に多くの、さらには高い賛成投票の回答があります。あなたは本当にあなたの答えが必要だと思いますか?そしてこの投稿に新しい品質を追加しますか?
L.ガタール

1
@ L.Guthardtはい、そう思います。私の答えは、問題の説明にある問題を解決するより普遍的な方法をもたらすと思います。ありがとうございました。
Aleksandr Neizvestnyi 2018年

2

このソリューションは、リフレクションオーバーヘッドのない汎用的なソリューションです。

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

私はあなたが交換することができると思うIsNullOrEmptyIsNullOrWhitespace
NibblyPig


1

私はもう少し一般的な私のものを共有する必要があると感じました。

使用法:

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

最初のバージョンはtry-catchを必要とするため低速ですが、見た目はきれいです。無効な文字列で何度も呼び出されない場合は、それほど重要ではありません。パフォーマンスに問題がある場合は、TryParseメソッドを使用する場合、ParseByのtypeパラメーターを指定する必要があることに注意してください。これは、コンパイラーによって推測できないためです。また、デリゲートを定義する必要があったのは、outキーワードをFunc <>内で使用できないためですが、少なくとも今回はコンパイラーが明示的なインスタンスを必要としません。

最後に、10進数、DateTime、Guidなど、他の構造体でも使用できます。


1

Generic NullableParserクラスのコードを見つけて適応させました。完全なコードは私のブログにあります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お探しのページが見つかりませんでした。リンクを
貼る

完全なコードを使用した@ Dirty-flow更新については申し訳ありません。決してより遅くない:)
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が数値でない場合、int.Parseは例外をスローしますが、これはnullを返すこととは異なります。
2016年

0

必要がない場合は、例外を使用しないでください。オーバーヘッドは恐ろしいものです。

TryParseのバリエーションは問題を解決します-(コードをよりエレガントに見せるために)クリエイティブにしたい場合は、3.5の拡張メソッドで何かをすることができますが、コードは多かれ少なかれ同じです。


0

デリゲートを使用すると、次のコードは、複数の構造体型のnull許容解析を必要とする場合に再利用性を提供できます。ここでは、.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));
    }
  }

0

これは古いトピックだと思いますが、簡単には言えません。

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


できますが、stringValの形式が正しくない場合は例外が発生します。int.Parseのドキュメントを参照してください
Alex

0

私はこれを思いついたのですが、これは私の要件を満たしています(フレームワークのTryParseの戻りをできるだけ近くにエミュレートする拡張メソッドを望んでいましたが、try {} catch {}ブロックがなく、コンパイラがフレームワークメソッド内のnull許容型)

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

以下のコードをお勧めします。変換エラーが発生した場合、例外を処理することができます。

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を入力しますか?personクラスのAgeプロパティ):

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); });
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.