c# - type - Nullable Typ als generischer Parameter möglich?




inherit generic type c# (7)

Ich möchte so etwas machen:

myYear = record.GetValueOrNull<int?>("myYear"),

Beachten Sie den Nullable-Typ als generischen Parameter.

Da die Funktion GetValueOrNull null zurückgeben konnte, war mein erster Versuch:

public static T GetValueOrNull<T>(this DbDataRecord reader, string columnName)
  where T : class
{
    object columnValue = reader[columnName];

    if (!(columnValue is DBNull))
    {
        return (T)columnValue;
    }
    return null;
}

Aber der Fehler, den ich jetzt bekomme, ist:

Der Typ 'int?' muss ein Referenztyp sein, um ihn als Parameter 'T' im generischen Typ oder in der generischen Methode zu verwenden

Recht! Nullable<int> ist eine struct ! Also habe ich versucht, die Klasseneinschränkung in eine struct ändern (und als Nebeneffekt kann null nicht mehr zurückgeben):

public static T GetValueOrNull<T>(this DbDataRecord reader, string columnName)
  where T : struct

Jetzt die Aufgabe:

myYear = record.GetValueOrNull<int?>("myYear");

Gibt den folgenden Fehler:

Der Typ 'int?' muss ein Nicht-Nullable-Werttyp sein, um ihn als Parameter 'T' im generischen Typ oder in der generischen Methode zu verwenden

Gibt es überhaupt einen nullbaren Typ als generischen Parameter an?


Ändern Sie den Rückgabetyp in Nullable, und rufen Sie die Methode mit dem Parameter non nullable auf

static void Main(string[] args)
{
    int? i = GetValueOrNull<int>(null, string.Empty);
}


public static Nullable<T> GetValueOrNull<T>(DbDataRecord reader, string columnName) where T : struct
{
    object columnValue = reader[columnName];

    if (!(columnValue is DBNull))
        return (T)columnValue;

    return null;
}

Dies kann ein toter Thread sein, aber ich neige dazu, Folgendes zu verwenden:

public static T? GetValueOrNull<T>(this DbDataRecord reader, string columnName)
where T : struct 
{
    return reader[columnName] as T?;
}

Ich habe das selbe Problem selbst gefunden.

... = reader["myYear"] as int?; funktioniert und ist sauber.

Es funktioniert mit jedem Typ ohne ein Problem. Wenn das Ergebnis DBNull ist, wird NULL zurückgegeben, da die Konvertierung fehlschlägt.


Ich weiß, das ist alt, aber hier ist eine andere Lösung:

public static bool GetValueOrDefault<T>(this SqlDataReader Reader, string ColumnName, out T Result)
{
    try
    {
        object ColumnValue = Reader[ColumnName];

        Result = (ColumnValue!=null && ColumnValue != DBNull.Value) ? (T)ColumnValue : default(T);

        return ColumnValue!=null && ColumnValue != DBNull.Value;
    }
    catch
    {
        // Possibly an invalid cast?
        return false;
    }
}

Nun, es ist dir egal, ob T Wert oder Referenztyp war. Nur wenn die Funktion wahr zurückgibt, haben Sie einen vernünftigen Wert aus der Datenbank. Verwendung:

...
decimal Quantity;
if (rdr.GetValueOrDefault<decimal>("YourColumnName", out Quantity))
{
    // Do something with Quantity
}

Dieser Ansatz ist sehr ähnlich zu int.TryParse("123", out MyInt);


Musste einfach etwas unglaublich ähnliches tun. Mein Code:

public T IsNull<T>(this object value, T nullAlterative)
{
    if(value != DBNull.Value)
    {
        Type type = typeof(T);
        if (type.IsGenericType && 
            type.GetGenericTypeDefinition() == typeof(Nullable<>).GetGenericTypeDefinition())
        {
            type = Nullable.GetUnderlyingType(type);
        }

        return (T)(type.IsEnum ? Enum.ToObject(type, Convert.ToInt32(value)) :
            Convert.ChangeType(value, type));
    }
    else 
        return nullAlternative;
}

Tun Sie einfach zwei Dinge zu Ihrem ursprünglichen Code - entfernen Sie die where Einschränkung, und ändern Sie die letzte return von return null , return default(T) . Auf diese Weise können Sie den gewünschten Typ zurückgeben.

Übrigens können Sie die Verwendung von is vermeiden, indem Sie Ihre if Anweisung in if (columnValue != DBNull.Value) .


public static T GetValueOrDefault<T>(this IDataRecord rdr, int index)
{
    object val = rdr[index];

    if (!(val is DBNull))
        return (T)val;

    return default(T);
}

Benutze es einfach so:

decimal? Quantity = rdr.GetValueOrDefault<decimal?>(1);
string Unit = rdr.GetValueOrDefault<string>(2);




generics