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

Che*_*hev 122 .net c# session null null-coalescing-operator

我喜欢null-coalescing运算符,因为它可以很容易地为可空类型分配默认值.

 int y = x ?? -1;
Run Code Online (Sandbox Code Playgroud)

这很好,除非我需要做一些简单的事情x.例如,如果我想检查Session,那么我通常最终不得不写更详细的东西.

我希望我能做到这一点:

string y = Session["key"].ToString() ?? "none";
Run Code Online (Sandbox Code Playgroud)

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

string y = Session["key"] == null ? "none" : Session["key"].ToString();
Run Code Online (Sandbox Code Playgroud)

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

string y = "none";
if (Session["key"] != null)
    y = Session["key"].ToString();
Run Code Online (Sandbox Code Playgroud)

尽管有效,但如果有更好的方法,我仍然很好奇.似乎无论我总是要引用Session["key"]两次; 一次检查,再次检查.有任何想法吗?

Bla*_*ear 183

关于什么

string y = (Session["key"] ?? "none").ToString();
Run Code Online (Sandbox Code Playgroud)

  • 这个力量很大. (79认同)
  • 我不喜欢这个,因为如果你在会话中填充的任何其他类型的对象超出了你的期望,你可能会在程序中隐藏一些微妙的错误.我宁愿使用安全演员,因为我认为它可能会更快地表现错误.它还避免在字符串对象上调用ToString(). (10认同)
  • @Matthew:否,因为Session值属于Object类型 (2认同)
  • 紧凑但多余. (2认同)

Jon*_*eet 130

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

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

...

string y = Session["key"].NullPreservingToString() ?? "none";
Run Code Online (Sandbox Code Playgroud)

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

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

...

string y = Session["key"].ToStringOrDefault("none");
Run Code Online (Sandbox Code Playgroud)

  • `.ToStringOrDefault()`简单而且优雅.一个很好的解决方 (16认同)
  • @NickLarsen:我说,一切都在适度.使用null的扩展方法非常有用,IMO - 只要它们*清楚*关于它们的作用. (10认同)
  • 我完全不同意这一点.`object`上的扩展方法是一个诅咒和垃圾代码库,并且在null`his`值上运行没有错误的扩展方法是纯粹的邪恶. (7认同)
  • @ one.beat.consumer:当纠正语法和拼写错误时,这很好 - 但改变一个人(任何人,不仅仅是我)明确故意选择的名字对我来说感觉不同.那时,我会在评论中建议. (6认同)
  • @ one.beat.consumer:是的.如果它只是*格式化(或任何拼写错误),那将是一回事,但改变作者对方法名称的选择超出了通常适当的编辑,IMO. (3认同)
  • 你被BlackBear打败了 (2认同)

And*_*mar 21

您也可以使用as,null如果转换失败,则会产生:

Session["key"] as string ?? "none"
Run Code Online (Sandbox Code Playgroud)

这将返回"none"即使有人塞进一个intSession["key"].

  • @Andomar:不,OP在一个对象(即`Session ["key"]`)上调用`ToString()`,他没有提到它的类型.它可以是任何类型的对象,不一定是字符串. (5认同)

Ry-*_*Ry- 13

如果它总是a string,你可以施放:

string y = (string)Session["key"] ?? "none";
Run Code Online (Sandbox Code Playgroud)

这有一个好处就是抱怨,而不是隐藏错误,如果有人填充int或某事Session["key"].;)


Ric*_*ard 10

所有建议的解决方案都很好,并回答了问题; 所以这只是略微延伸.目前,大多数答案仅处理空验证和字符串类型.您可以扩展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;
}
Run Code Online (Sandbox Code Playgroud)

  • `T value = source [key]为T; 返回值?默认值;` (3认同)

Tim*_*mwi 7

我们使用一种叫做的方法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());
Run Code Online (Sandbox Code Playgroud)

资源

/// <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();
    }
}
Run Code Online (Sandbox Code Playgroud)


tva*_*son 6

对于一次性,我的偏好是使用安全强制转换为字符串,以防与密钥一起存储的对象不是一个.使用ToString()可能没有您想要的结果.

var y = Session["key"] as string ?? "none";
Run Code Online (Sandbox Code Playgroud)

正如@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 }
    }
}
Run Code Online (Sandbox Code Playgroud)

用作

 var session = new SessionWrapper(Session);

 string key = session.Key;
 int maxAllowed = session.maxAllowed;
Run Code Online (Sandbox Code Playgroud)