Что такое правильный способ, чтобы проверить на NULL значения?
мне нравится оператор null-coalescing, потому что он позволяет легко назначить значение по умолчанию для типов с нулевым значением.
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"]
дважды: один раз для проверки, и снова на задание. Есть идеи?
10 ответов:
Если вы часто это делаете конкретно
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
метод, похожий на ответ, опубликованный Джоном скитом.простой универсальный метод расширения, который принимает строку в качестве ключа, а затем проверяет тип объекта сеанса. Если объект имеет значение 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' );
ответ скита является лучшим - в частности, я думаю, что его
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, которые не поддерживают ?.
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");
Это очень полезно для nullable типов тоже. Например:
decimal? v; ... IsNull.Substitute(v,v.Value,0); ....