什么是检查空值的正确方法?

我喜欢null-coalescing运算符,因为它可以很容易地为可为null的types分配默认值。

int y = x ?? -1; 

这很好,除非我需要用x做简单的事情。 例如,如果我想检查Session ,那么通常最终必须写更详细的内容。

我希望我能做到这一点:

 string y = Session["key"].ToString() ?? "none"; 

但是你不能这样做,因为.ToString()在空检查之前被调用,所以如果Session["key"]为空,它就会失败。 我最终这样做:

 string y = Session["key"] == null ? "none" : Session["key"].ToString(); 

在我看来,它比三线式更好,

 string y = "none"; if (Session["key"] != null) y = Session["key"].ToString(); 

即使这样做,我仍然好奇,如果有更好的方法。 似乎不pipe我总是必须参考Session["key"]两次; 一次为检查,再次为任务。 有任何想法吗?

关于什么

 string y = (Session["key"] ?? "none").ToString(); 

如果你经常ToString()来做这个那么你可以写一个扩展方法:

 public static string NullPreservingToString(this object input) { return input == null ? null : input.ToString(); } ... string y = Session["key"].NullPreservingToString() ?? "none"; 

或者采取默认的方法,当然是:

 public static string ToStringOrDefault(this object input, string defaultValue) { return input == null ? defaultValue : input.ToString(); } ... string y = Session["key"].ToStringOrDefault("none"); 

你也可以使用as ,如果转换失败则返回null

 Session["key"] as string ?? "none" 

即使某人在Session["key"]填充了一个int ,也会返回"none"

如果它总是一个string ,你可以投射:

 string y = (string)Session["key"] ?? "none"; 

这具有抱怨的优点,而不是隐藏错误,如果有人在Session["key"]填充int或某物。 ;)

所有build议的解决scheme都是好的,并回答这个问题。 所以这只是略微扩展。 目前大多数的答案只处理空validation和stringtypes。 您可以扩展StateBag对象以包含通用的GetValueOrDefault方法,类似于Jon Skeet发布的答案。

一个简单的通用扩展方法,接受一个string作为一个键,然后键入检查会话对象。 如果对象为null或不是相同的types,则返回默认值,否则强制types返回会话值。

像这样的东西

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

我们使用一个名为NullOr的方法。

用法

 // 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()); 

资源

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

我偏好一个closures,将使用一个安全的强制转换,以防与钥匙存储的对象不是一个。 使用ToString()可能没有你想要的结果。

 var y = Session["key"] as string ?? "none"; 

正如@Jon Skeet所说的,如果你发现自己做了很多扩展方法,或者更好,也许是一个强types的SessionWrapper类的扩展方法。 即使没有扩展方法,强types包装可能是一个好主意。

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

用作

  var session = new SessionWrapper(Session); string key = session.Key; int maxAllowed = session.maxAllowed; 

创build一个辅助function

 public static String GetValue( string key, string default ) { if ( Session[ key ] == null ) { return default; } return Session[ key ].toString(); } string y = GetValue( 'key', 'none' ); 

Skeet的答案是最好的 – 特别是我认为他的ToStringOrNull()非常优雅,最适合您的需求。 我想给扩展方法列表添加一个选项:

返回null的原始对象或默认string值:

 // 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"); 

使用var作为返回的值,因为它将作为原始input的types返回,仅当为null时作为默认string

这是我的小型安全的“猫王操作员”版本的.NET不支持?

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

第一个论据是被testing的对象。 其次是function。 第三是空值。 所以对于你的情况:

 IsNull.Substitute(Session["key"],s=>s.ToString(),"none"); 

对于可空types也是非常有用的。 例如:

 decimal? v; ... IsNull.Substitute(v,v.Value,0); ....