it-swarm.com.de

Konvertiere String in nullbaren Typ (int, double, etc ...)

Ich versuche eine Datenkonvertierung durchzuführen. Leider befinden sich viele Daten in Strings, wo es ints oder double usw. sein sollte.

Also, was ich habe, ist so etwas wie:

double? amount = Convert.ToDouble(strAmount);

Das Problem bei diesem Ansatz ist, wenn strAmount leer ist, wenn es leer ist, soll der Betrag null sein. Wenn ich ihn der Datenbank hinzufüge, ist die Spalte null. Also habe ich folgendes geschrieben:

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

Jetzt funktioniert das gut, aber ich habe jetzt fünf Zeilen Code anstelle von einer. Dies erschwert die Lesbarkeit, insbesondere wenn viele Spalten konvertiert werden müssen.

Ich dachte, ich würde eine Erweiterung der String-Klasse und der generischen verwenden, um den Typ zu übergeben. Dies liegt daran, dass es sich um ein Double, ein Int oder ein Long handeln könnte. Also habe ich Folgendes versucht:

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

Aber ich bekomme die Fehlermeldung: Kann den Typ 'string' nicht in 'T?'

Gibt es einen Weg, dies zu umgehen? Ich bin nicht sehr vertraut mit dem Erstellen von Methoden mit Generika.

130
Nathan Koop

Eine andere Sache zu beachten ist, dass die Zeichenfolge selbst null sein kann.

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;
}
150
Joel Coehoorn

Sie können die folgende Erweiterungsmethode verwenden:

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

Auf diese Weise können Sie dies tun:

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

Was ist damit:


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

Dies berücksichtigt natürlich nicht den Konvertierungsfehler.

25
John Kraft

Ich habe diesen generischen Typkonverter geschrieben. Es funktioniert mit Nullable- und Standardwerten und konvertiert zwischen allen konvertierbaren Typen - nicht nur Strings. Es werden alle Arten von Szenarien behandelt, die Sie erwarten (Standardwerte, Nullwerte, andere Werte usw.).

Ich benutze dies seit ungefähr einem Jahr in Dutzenden von Produktionsprogrammen, daher sollte es ziemlich solide sein.

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

Vielleicht möchten Sie versuchen:

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

machen Sie Ihren eigenen Null-Check und geben Sie bei Bedarf int? zurück. Das solltest du auch in einen try {} Einwickeln.

9
Andrew Bullock

Probieren Sie es aus ...

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

Dann nenne es so ...

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
Adam Robinson

Sie können Folgendes mit Objekten verwenden, dies funktioniert jedoch leider nicht mit Zeichenfolgen.

double? amount = (double?)someObject;

Ich verwende es zum Umbrechen einer Sitzungsvariablen in eine Eigenschaft (auf einer Basisseite). Meine tatsächliche Verwendung ist also (auf meiner Basisseite):

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

Ich kann in der Seitenlogik nach null suchen:

if (base.OrganisationID == null)
    // do stuff
5
Scotty.NET

Ich mag Joels Antwort, aber ich habe sie leicht modifiziert, da ich kein Fan von Essensausnahmen bin.

    /// <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
Colin Place
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

Es gibt eine generische Lösung (für jeden Typ). Die Benutzerfreundlichkeit ist gut, aber die Implementierung sollte verbessert werden: http://cleansharp.de/wordpress/2011/05/generischer-typeconverter/

Auf diese Weise können Sie sehr sauberen Code wie folgt schreiben:

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

und auch:

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>();
3
Pavel Hodek

Hier ist etwas basierend auf akzeptierten Antworten. Ich habe den Versuch/Fang entfernt, um sicherzustellen, dass alle Ausnahmen nicht verschluckt und nicht behandelt werden. Stellen Sie außerdem sicher, dass die Rückgabevariable (in akzeptierter Antwort) niemals zweimal umsonst initialisiert wird.

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

Daran führt kein Weg vorbei. Nullable ist ebenso wie Ihre Methode darauf beschränkt, nur Werttypen als Argument zu verwenden. String ist ein Referenztyp und daher mit dieser Deklaration nicht kompatibel.

3
JaredPar

Eine andere Variante. Dieses

  • Schluckt keine Ausnahmen
  • Löst ein NotSupportedException aus, wenn der Typ nicht von string konvertiert werden kann. Zum Beispiel eine benutzerdefinierte Struktur ohne Typkonverter.
  • Andernfalls wird ein (T?)null wenn die Zeichenfolge nicht analysiert werden kann. Keine Notwendigkeit, auf Null oder Leerzeichen zu prüfen.
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;
}
2
BurnsBA

Mein Beispiel für anonyme Typen:

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
ADM-IT

Fügen wir dem Stack noch eine ähnliche Lösung hinzu. Dieser analysiert auch Enums und sieht gut aus. Sehr sicher.

/// <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
Pangamma

Die generische Antwort von "Joel Coehoorn" ist gut.

Aber dies ist ein anderer Weg, ohne diese GetConverter... oder try/catch blocks ... (Ich bin nicht sicher, aber dies kann in einigen Fällen eine bessere Leistung haben):

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

Verwendung ist wie folgt:

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
0
S.Serpooshan