122

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

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

即使这样有效,我仍然很好奇是否有更好的方法。似乎不管我总是要引用Session["key"]两次;一次用于检查,再次用于分配。有任何想法吗?

4

10 回答 10

182

关于什么

string y = (Session["key"] ?? "none").ToString();
于 2012-03-20T14:12:47.907 回答
130

如果您经常专门这样做,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");
于 2012-03-20T14:14:32.383 回答
21

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

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

"none"即使有人塞了一个intin ,这也会返回Session["key"]

于 2012-03-20T18:36:11.907 回答
13

如果它总是 a string,你可以转换:

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

这样做的好处是,如果有人intSession["key"]. ;)

于 2012-03-20T14:15:38.013 回答
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;
}
于 2012-03-20T16:53:21.870 回答
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());

资源

/// <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();
    }
}
于 2012-03-22T15:32:26.540 回答
6

我的偏好是一次性使用安全强制转换为字符串,以防与密钥一起存储的对象不是一个。使用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;
于 2012-03-20T19:12:20.170 回答
3

创建辅助功能

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


string y = GetValue( 'key', 'none' );
于 2012-03-20T14:14:02.820 回答
2

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

于 2012-03-20T18:35:29.130 回答
0

对于不支持 ? 的 .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);
    }
}

第一个参数是测试对象。二是功能。第三是空值。所以对于你的情况:

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

它对于可空类型也非常有用。例如:

decimal? v;
...
IsNull.Substitute(v,v.Value,0);
....
于 2016-06-01T08:57:00.457 回答