valor - validar int null c#
¿Cuál es la forma correcta de verificar valores nulos? (10)
Me encanta el operador de fusión nula porque facilita la asignación de un valor predeterminado para los tipos que aceptan nulos.
int y = x ?? -1;
Eso es genial, excepto si necesito hacer algo simple con x
. Por ejemplo, si quiero verificar la Session
, generalmente termino escribiendo algo más detallado.
Ojalá pudiera hacer esto:
string y = Session["key"].ToString() ?? "none";
Pero no puede porque se llama a .ToString()
antes de la verificación nula, por lo que falla si Session["key"]
es nulo. Termino haciendo esto:
string y = Session["key"] == null ? "none" : Session["key"].ToString();
Funciona y es mejor, en mi opinión, que la alternativa de tres líneas:
string y = "none";
if (Session["key"] != null)
y = Session["key"].ToString();
Aunque eso funciona, todavía tengo curiosidad de saber si hay una mejor manera. Parece que no importa lo que siempre tenga que hacer referencia a Session["key"]
dos veces; una vez para el control, y otra vez para la tarea. ¿Algunas ideas?
Este es mi pequeño tipo seguro "Elvis operator" para las versiones de .NET que no son compatibles?
public class IsNull
{
public static O Substitute<I,O>(I obj, Func<I,O> fn, O nullValue=default(O))
{
if (obj == null)
return nullValue;
else
return fn(obj);
}
}
El primer argumento es el objeto probado. En segundo lugar está la función. Y el tercero es el valor nulo. Entonces para tu caso:
IsNull.Substitute(Session["key"],s=>s.ToString(),"none");
También es muy útil para los tipos que aceptan nulos. Por ejemplo:
decimal? v;
...
IsNull.Substitute(v,v.Value,0);
....
La respuesta de Skeet es la mejor, en particular creo que su ToStringOrNull()
es bastante elegante y se adapta mejor a tus necesidades. Quería agregar una opción más a la lista de métodos de extensión:
Devuelve el objeto original o el valor de cadena predeterminado para null :
// Method:
public static object OrNullAsString(this object input, string defaultValue)
{
if (defaultValue == null)
throw new ArgumentNullException("defaultValue");
return input == null ? defaultValue : input;
}
// Example:
var y = Session["key"].OrNullAsString("defaultValue");
Use var
para el valor devuelto, ya que volverá como el tipo de entrada original, solo como la cadena predeterminada cuando es null
Mi preferencia, por una sola vez, sería usar un cast de seguridad para encadenar en caso de que el objeto almacenado con la llave no sea uno. Es posible que el uso de ToString()
no tenga los resultados que desea.
var y = Session["key"] as string ?? "none";
Como dice @Jon Skeet, si te encuentras haciendo esto mucho, un método de extensión o, mejor aún, tal vez un método de extensión junto con una clase SessionWrapper fuertemente tipada. Incluso sin el método de extensión, la envoltura fuertemente tipada podría ser una buena idea.
public class SessionWrapper
{
private HttpSessionBase Session { get; set; }
public SessionWrapper( HttpSessionBase session )
{
Session = session;
}
public SessionWrapper() : this( HttpContext.Current.Session ) { }
public string Key
{
get { return Session["key"] as string ?? "none";
}
public int MaxAllowed
{
get { return Session["maxAllowed"] as int? ?? 10 }
}
}
Usado como
var session = new SessionWrapper(Session);
string key = session.Key;
int maxAllowed = session.maxAllowed;
Qué pasa
string y = (Session["key"] ?? "none").ToString();
Si con frecuencia hace esto específicamente con ToString()
entonces puede escribir un método de extensión:
public static string NullPreservingToString(this object input)
{
return input == null ? null : input.ToString();
}
...
string y = Session["key"].NullPreservingToString() ?? "none";
O un método que toma un valor predeterminado, por supuesto:
public static string ToStringOrDefault(this object input, string defaultValue)
{
return input == null ? defaultValue : input.ToString();
}
...
string y = Session["key"].ToStringOrDefault("none");
Si siempre será una string
, puede lanzar:
string y = (string)Session["key"] ?? "none";
Esto tiene la ventaja de quejarse en lugar de ocultar el error si alguien inserta un int
o algo en Session["key"]
. ;)
También puede usar as
, que produce null
si la conversión falla:
Session["key"] as string ?? "none"
Esto devolvería "none"
incluso si alguien metió un int
en Session["key"]
.
Todas las soluciones sugeridas son buenas y responden la pregunta; así que esto es solo extenderlo ligeramente. Actualmente, la mayoría de las respuestas solo se refieren a validación nula y tipos de cadenas. Puede extender el objeto StateBag
para incluir un método genérico GetValueOrDefault
, similar a la respuesta publicada por Jon Skeet.
Un método de extensión genérico simple que acepta una cadena como clave y luego escribe revisa el objeto de sesión. Si el objeto es nulo o no es del mismo tipo, se devuelve el valor predeterminado, de lo contrario, el valor de la sesión se devuelve fuertemente tipado.
Algo como esto
/// <summary>
/// Gets a value from the current session, if the type is correct and present
/// </summary>
/// <param name="key">The session key</param>
/// <param name="defaultValue">The default value</param>
/// <returns>Returns a strongly typed session object, or default value</returns>
public static T GetValueOrDefault<T>(this HttpSessionState source, string key, T defaultValue)
{
// check if the session object exists, and is of the correct type
object value = source[key]
if (value == null || !(value is T))
{
return defaultValue;
}
// return the session object
return (T)value;
}
Usamos un método llamado NullOr
.
Uso
// Call ToString() if it’s not null, otherwise return null
var str = myObj.NullOr(obj => obj.ToString());
// Supply default value for when it’s null
var str = myObj.NullOr(obj => obj.ToString()) ?? "none";
// Works with nullable return values, too —
// this is properly typed as “int?” (nullable int)
// even if “Count” is just int
var count = myCollection.NullOr(coll => coll.Count);
// Works with nullable input types, too
int? unsure = 47;
var sure = unsure.NullOr(i => i.ToString());
Fuente
/// <summary>Provides a function delegate that accepts only value types as return types.</summary>
/// <remarks>This type was introduced to make <see cref="ObjectExtensions.NullOr{TInput,TResult}(TInput,FuncStruct{TInput,TResult})"/>
/// work without clashing with <see cref="ObjectExtensions.NullOr{TInput,TResult}(TInput,FuncClass{TInput,TResult})"/>.</remarks>
public delegate TResult FuncStruct<in TInput, TResult>(TInput input) where TResult : struct;
/// <summary>Provides a function delegate that accepts only reference types as return types.</summary>
/// <remarks>This type was introduced to make <see cref="ObjectExtensions.NullOr{TInput,TResult}(TInput,FuncClass{TInput,TResult})"/>
/// work without clashing with <see cref="ObjectExtensions.NullOr{TInput,TResult}(TInput,FuncStruct{TInput,TResult})"/>.</remarks>
public delegate TResult FuncClass<in TInput, TResult>(TInput input) where TResult : class;
/// <summary>Provides extension methods that apply to all types.</summary>
public static class ObjectExtensions
{
/// <summary>Returns null if the input is null, otherwise the result of the specified lambda when applied to the input.</summary>
/// <typeparam name="TInput">Type of the input value.</typeparam>
/// <typeparam name="TResult">Type of the result from the lambda.</typeparam>
/// <param name="input">Input value to check for null.</param>
/// <param name="lambda">Function to apply the input value to if it is not null.</param>
public static TResult NullOr<TInput, TResult>(this TInput input, FuncClass<TInput, TResult> lambda) where TResult : class
{
return input == null ? null : lambda(input);
}
/// <summary>Returns null if the input is null, otherwise the result of the specified lambda when applied to the input.</summary>
/// <typeparam name="TInput">Type of the input value.</typeparam>
/// <typeparam name="TResult">Type of the result from the lambda.</typeparam>
/// <param name="input">Input value to check for null.</param>
/// <param name="lambda">Function to apply the input value to if it is not null.</param>
public static TResult? NullOr<TInput, TResult>(this TInput input, Func<TInput, TResult?> lambda) where TResult : struct
{
return input == null ? null : lambda(input);
}
/// <summary>Returns null if the input is null, otherwise the result of the specified lambda when applied to the input.</summary>
/// <typeparam name="TInput">Type of the input value.</typeparam>
/// <typeparam name="TResult">Type of the result from the lambda.</typeparam>
/// <param name="input">Input value to check for null.</param>
/// <param name="lambda">Function to apply the input value to if it is not null.</param>
public static TResult? NullOr<TInput, TResult>(this TInput input, FuncStruct<TInput, TResult> lambda) where TResult : struct
{
return input == null ? null : lambda(input).Nullable();
}
}
crear una función auxiliar
public static String GetValue( string key, string default )
{
if ( Session[ key ] == null ) { return default; }
return Session[ key ].toString();
}
string y = GetValue( ''key'', ''none'' );