简体   繁体   English

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

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

I love the null-coalescing operator because it makes it easy to assign a default value for nullable types. 我喜欢null-coalescing运算符,因为它可以很容易地为可空类型分配默认值。

 int y = x ?? -1;

That's great, except if I need to do something simple with x . 这很好,除非我需要用x做一些简单的事情。 For instance, if I want to check Session , then I usually end up having to write something more verbose. 例如,如果我想检查Session ,那么我通常最终必须编写更详细的内容。

I wish I could do this: 我希望我能做到这一点:

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

But you can't because the .ToString() gets called before the null check so it fails if Session["key"] is null. 但是你不能因为.ToString()在null检查之前被调用,所以如果Session["key"]为null则它会失败。 I end up doing this: 我最终这样做了:

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

It works and is better, in my opinion, than the three-line alternative: 在我看来,它比三线替代方案更有效,也更好:

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

Even though that works I am still curious if there is a better way. 尽管有效,但如果有更好的方法,我仍然很好奇。 It seems no matter what I always have to reference Session["key"] twice; 似乎无论我总是两次引用Session["key"] ; once for the check, and again for the assignment. 一次检查,再次检查。 Any ideas? 有任何想法吗?

关于什么

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

If you're frequently doing this specifically with ToString() then you could write an extension method: 如果您经常使用ToString()进行此操作那么您可以编写一个扩展方法:

public static string NullPreservingToString(this object input)
{
    return input == null ? null : input.ToString();
}

...

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

Or a method taking a default, of course: 或者采取默认的方法,当然:

public static string ToStringOrDefault(this object input, string defaultValue)
{
    return input == null ? defaultValue : input.ToString();
}

...

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

You could also use as , which yields null if the conversion fails: 您也可以使用as ,如果转换失败,则返回null

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

This would return "none" even if someone stuffed an int in Session["key"] . 即使有人在Session["key"]填充了int ,这也会返回"none"

If it will always be a string , you can cast: 如果它总是一个string ,你可以强制转换:

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

This has the advantage of complaining instead of hiding the mistake if someone stuffs an int or something in Session["key"] . 如果有人在Session["key"]填充了int或者某些东西,这就有了抱怨而不是隐藏错误的优点。 ;) ;)

All of the suggested solutions are good, and answer the question; 所有建议的解决方案都很好,并回答了问题; so this is just to extend on it slightly. 所以这只是略微延伸。 Currently the majority of answers only deal with null validation and string types. 目前,大多数答案仅处理空验证和字符串类型。 You could extend the StateBag object to include a generic GetValueOrDefault method, similar to the answer posted by Jon Skeet. 您可以扩展StateBag对象以包含通用的GetValueOrDefault方法,类似于Jon Skeet发布的答案。

A simple generic extension method that accepts a string as a key, and then type checks the session object. 一种简单的通用扩展方法,它接受字符串作为键,然后键入检查会话对象。 If the object is null or not the same type, the default is returned, otherwise the session value is returned strongly typed. 如果对象为null或不是相同类型,则返回默认值,否则返回强类型会话值。

Something like this 像这样的东西

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

We use a method called NullOr . 我们使用一种名为NullOr的方法。

Usage 用法

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

Source 资源

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

My preference, for a one off, would be to use a safe cast to string in case the object stored with the key isn't one. 对于一次性,我的偏好是使用安全强制转换为字符串,以防与密钥一起存储的对象不是一个。 Using ToString() may not have the results you want. 使用ToString()可能没有您想要的结果。

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

As @Jon Skeet says, if you find yourself doing this a lot an extension method or, better, yet maybe an extension method in conjunction with a strongly typed SessionWrapper class. 正如@Jon Skeet所说,如果你发现自己做了很多扩展方法,或者更好,但可能是一个与强类型SessionWrapper类结合的扩展方法。 Even without the extension method, the strongly typed wrapper might be a good 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 }
    }
}

Used as 用作

 var session = new SessionWrapper(Session);

 string key = session.Key;
 int maxAllowed = session.maxAllowed;

create an auxiliary 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's answer is the best - in particularly I think his ToStringOrNull() is quite elegant and suits your need best. Skeet的答案是最好的 - 特别是我认为他的ToStringOrNull()非常优雅,最适合您的需求。 I wanted to add one more option to the list of extension methods: 我想在扩展方法列表中再添加一个选项:

Return original object or default string value for null : 返回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 for the returned value as it will come back as the original input's type, only as the default string when null 使用var作为返回值,因为它将作为原始输入的类型返回,仅作为null时的默认字符串

This is my little type safe "Elvis operator" for versions of .NET that do not support ?. 对于不支持的.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);
    }
}

First argument is the tested object. 第一个参数是测试对象。 Second is the function. 第二是功能。 And third is the null value. 第三个是空值。 So for your case: 所以对于你的情况:

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

It is very useful for nullable types too. 它对于可空类型也非常有用。 For example: 例如:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM