文字列を NULL 許容の int に解析する方法
質問
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 に直接解析する組み込みフレームワーク メソッドがあるかどうかを知りたいと思っています。
解決
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
は の 文字列を int に解析する方法。
他のヒント
条件演算子とキャストできることを使用して、これを 1 行で実行できます。 null
null 許容型に変換します (2 行。既存の 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に直接解析する組み込みのフレームワークメソッドがあるかどうかを知ることにもっと興味がありますか?
値が 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.
これを試して:
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?);
}
null を解析する要件として、これが気に入っています。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)" があることだけを必要とするジェネリック ソリューションです。これは、数値、ブール値、DateTime などに機能します。
他の答えはすべて忘れて構いません。素晴らしい一般的な解決策があります。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 フォーラムの 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);
解析が不可能な場合に備えてデフォルト値を定義できる機能を備えた、文字列を 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);
}
私は、null 許容 int に直接解析する組み込みフレームワーク メソッドがあるかどうかを知りたいと思っています。
ありません。
もう少し一般的な私のものを共有する必要があると感じました。
使用法:
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 の型パラメーターを指定する必要があることに注意してください。また、 out キーワードは Func<> 内で使用できないため、デリゲートを定義する必要がありましたが、少なくとも今回のコンパイラは明示的なインスタンスを必要としません。
最後に、他の構造体でも使用できます。10 進数、DateTime、Guid など。
Generic NullableParser クラス用のコードをいくつか見つけて適合させました。完全なコードは私のブログにあります Null 許容 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;
}
}
}
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 の拡張メソッドを使用して何かを行うこともできますが、コードはほぼ同じになります。
複数の構造型に対して 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));
}
}
私はこれを思いつきました。これは私の要件を満たしています(拡張メソッドはフレームワークの 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;
}
以下のコードをお勧めします。変換エラーが発生した場合、例外を処理できる場合があります。
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);
}
}
この拡張メソッドをコード内で使用します (fill int?人物クラスの 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); });
これは古いトピックであることは承知していますが、次のことはできませんか?
(Nullable<int>)int.Parse(stringVal);
?