Ответ 1
Что насчет
string y = (Session["key"] ?? "none").ToString();
Мне нравится оператор с нулевым коалесцированием, потому что он упрощает присвоение значения по умолчанию для типов с нулевым значением.
int y = x ?? -1;
Это здорово, если только мне не нужно делать что-то простое с x
. Например, если я хочу проверить Session
, то обычно мне приходится писать что-то более подробное.
Я хотел бы сделать это:
string y = Session["key"].ToString() ?? "none";
Но вы не можете, потому что .ToString()
вызывается до нулевой проверки, поэтому он терпит неудачу, если 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"
Это вернет "none"
, даже если кто-то наполнил int
в Session["key"]
.
Если он всегда будет string
, вы можете использовать:
string y = (string)Session["key"] ?? "none";
У этого есть преимущество жаловаться вместо того, чтобы скрывать ошибку, если кто-то наполняет int
или что-то в Session["key"]
.;)
Все предлагаемые решения хороши и отвечают на вопрос; так что это просто немного растянуть на нем. В настоящее время большинство ответов касаются только нулевой валидации и типов строк. Вы можете расширить объект StateBag
, включив в него общий метод GetValueOrDefault
, похожий на ответ, отправленный Джоном Скитом.
Простой общий метод расширения, который принимает строку как ключ, а затем вводит проверку объекта сеанса. Если объект имеет нулевой или не тот же тип, возвращается значение по умолчанию, в противном случае значение сеанса возвращается строго типизированным.
Что-то вроде этого
/// <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' );
Лучший ответ - это, в частности, я думаю, что его ToStringOrNull()
довольно элегантен и подходит вам лучше всего. Я хотел добавить еще один вариант в список методов расширения:
// 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
Это мой маленький безопасный тип "Elvis operator" для версий .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);
....