簡體   English   中英

檢查空值的正確方法是什么?

[英]What is the proper way to check for null values?

我喜歡null-coalescing運算符,因為它可以很容易地為可空類型分配默認值。

 int y = x ?? -1;

這很好,除非我需要用x做一些簡單的事情。 例如,如果我想檢查Session ,那么我通常最終必須編寫更詳細的內容。

我希望我能做到這一點:

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

但是你不能因為.ToString()在null檢查之前被調用,所以如果Session["key"]為null則它會失敗。 我最終這樣做了:

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

在我看來,它比三線替代方案更有效,也更好:

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

盡管有效,但如果有更好的方法,我仍然很好奇。 似乎無論我總是兩次引用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或者某些東西,這就有了抱怨而不是隱藏錯誤的優點。 ;)

所有建議的解決方案都很好,並回答了問題; 所以這只是略微延伸。 目前,大多數答案僅處理空驗證和字符串類型。 您可以擴展StateBag對象以包含通用的GetValueOrDefault方法,類似於Jon Skeet發布的答案。

一種簡單的通用擴展方法,它接受字符串作為鍵,然后鍵入檢查會話對象。 如果對象為null或不是相同類型,則返回默認值,否則返回強類型會話值。

像這樣的東西

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

對於一次性,我的偏好是使用安全強制轉換為字符串,以防與密鑰一起存儲的對象不是一個。 使用ToString()可能沒有您想要的結果。

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

正如@Jon Skeet所說,如果你發現自己做了很多擴展方法,或者更好,但可能是一個與強類型SessionWrapper類結合的擴展方法。 即使沒有擴展方法,強類型包裝也許是個好主意。

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;

創建一個輔助功能

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的原始對象或默認字符串值:

// 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作為返回值,因為它將作為原始輸入的類型返回,僅作為null時的默認字符串

對於不支持的.NET版本,這是我的小型安全“Elvis操作符”。

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

第一個參數是測試對象。 第二是功能。 第三個是空值。 所以對於你的情況:

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

它對於可空類型也非常有用。 例如:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM