null 값을 확인하는 적절한 방법은 무엇입니까?


122

nullable 형식에 대한 기본값을 쉽게 할당 할 수 있기 때문에 null 통합 연산자를 좋아합니다.

 int y = x ?? -1;

.NET으로 간단한 작업을 수행해야하는 경우를 제외하고는 훌륭 x합니다. 예를 들어을 확인하려면 Session일반적으로 더 자세한 내용을 작성해야합니다.

나는 이것을 할 수 있기를 바랍니다.

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

그러나 .ToString()null 검사 전에 호출되므로 null이면 실패합니다 Session["key"]. 나는 이것을 끝낸다 :

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

제 생각에는 3 줄 대안보다 작동하고 더 좋습니다.

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

작동하지만 더 나은 방법이 있는지 여전히 궁금합니다. 내가 항상 Session["key"]두 번 언급해야하는 것이 무엇이든 상관없는 것 같습니다 . 확인을 위해 한 번, 할당을 위해 다시. 어떤 아이디어?


20
이것은 C #에 Groovy.? 와 같은 "안전한 탐색 연산자"( ) 가 있기를 바랍니다 .
카메론

2
@Cameron : C #에서 nullable 형식 (참조 형식 포함)을 모나드로 처리 할 수 ​​있기를 원하므로 "안전한 탐색 연산자"가 필요하지 않습니다.
존 퍼디

3
null 참조의 발명가는 이것을 "10 억 달러의 실수"라고 불렀고 나는 동의하는 경향이 있습니다. 참조 infoq.com/presentations/...
제이미 이데에게

그의 실제 실수는 nullable 유형과 non-nullabel 유형의 안전하지 않은 (언어 적용이 아닌) 혼합입니다.
MSalters 2012 년

@JamieIde 매우 흥미로운 링크에 감사드립니다. :)
BobRodes

답변:


182

이건 어떤가요

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

79
이것으로 힘이 강하다.
Chev

2
@Matthew : 아니요, 세션 값은 Object
BlackBear

1
@BlackBear 그러나 반환 된 값은 아마도 문자열 일 가능성이
높으므로

이것은 내 질문에 대한 가장 직접적인 대답이므로 대답을 표시하고 있지만 Jon Skeet의 확장 방법 .ToStringOrDefault()이 선호하는 방법입니다. 그러나 나는 Jon의 확장 방법 내 에서이 답변을 사용하고 있습니다.)
Chev

10
세션에 다른 유형의 개체가 포함되어 있으면 프로그램에서 미묘한 버그를 숨길 수 있기 때문에 이것을 싫어합니다. 오류를 더 빨리 표면화 할 가능성이 높기 때문에 안전한 캐스트를 사용하고 싶습니다. 또한 문자열 객체에서 ToString () 호출을 방지합니다.
tvanfosson

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

16
.ToStringOrDefault()간단하고 우아합니다. 좋은 솔루션입니다.
Chev

7
나는 이것에 전혀 동의 할 수 없습니다. 의 확장 메서드 object는 저주이며 코드 기반을 망가 뜨리고 null this값에 오류없이 작동하는 확장 메서드 는 순수한 악입니다.
Nick Larsen 2012 년

10
@NickLarsen : 모든 것이 적당하다고 말합니다. 그래서 그들이있는 한 - 널 (null)와 함께 작업 IMO, 매우 유용 할 수 있습니다 확장 방법을 명확 그들이 무엇에 대해.
Jon Skeet 2012 년

3
@ one.beat.consumer : 네. 형식화 (또는 오타) 있었다면 그것은 한 가지 였을 것입니다. 그러나 저자가 선택한 메소드 이름을 변경하는 것은 일반적으로 적절한 편집인 IMO를 넘어서는 것입니다.
Jon Skeet

6
@ one.beat.consumer : 문법과 오타를 고쳐도 괜찮습니다.하지만 누군가 (나뿐만 아니라 누구나)가 분명히 고의로 선택한 이름을 변경하는 것은 나에게 다르게 느껴집니다. 그 시점에서 대신 댓글로 제안합니다.
Jon Skeet

21

를 사용할 수도 있습니다 . 변환이 실패하면 다음 as과 같이 산출 null됩니다.

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

이것은 반환 "none"누군가가 박제 경우에도 int의를 Session["key"].


1
이것은 ToString()처음에 필요하지 않을 때만 작동합니다 .
Abel

1
아직 아무도이 답변을 반대하지 않았다는 것이 놀랍습니다. 이것은 OP가 원하는 것과 의미 상 완전히 다릅니다.
Timwi

@Timwi : OP는 ToString()문자열을 포함하는 객체를 문자열로 변환하는 데 사용 합니다. obj as string또는으로도 동일하게 수행 할 수 있습니다 (string)obj. ASP.NET에서는 매우 일반적인 상황입니다.
Andomar

5
@Andomar : 아니요, OP는 그가 언급하지 않은 유형 ToString()의 객체 (즉, Session["key"])를 호출 하고 있습니다. 모든 종류의 객체 일 수 있으며 반드시 문자열 일 필요는 없습니다.
Timwi

13

항상 string이면 다음을 전송할 수 있습니다.

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

이것은 누군가가 .NET에서 int무언가를 채우면 실수를 숨기는 대신 불평하는 장점이 있습니다 Session["key"]. ;)


10

제안 된 모든 솔루션이 훌륭하며 질문에 답하십시오. 그래서 이것은 약간 확장하는 것입니다. 현재 대부분의 답변은 null 유효성 검사 및 문자열 유형 만 처리합니다. StateBag객체를 확장하여 일반GetValueOrDefaultJon 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;
}

1
이 확장 방법에 대한 사용 샘플을 포함 할 수 있습니까? StateBag는 세션이 아닌 뷰 상태를 처리하지 않습니까? ASP.NET MVC 3을 사용하고 있으므로 상태보기에 대한 간단한 액세스 권한이 없습니다. 확장하고 싶다고 생각합니다 HttpSessionState.
Chev

이 대답은 성공하면 3x 및 2 캐스트 값을 검색해야합니다. (사전이라는 것을 알고 있지만 초보자는 값 비싼 방법에 대해 유사한 관행을 사용할 수 있습니다.)
Jake Berger

3
T value = source[key] as T; return value ?? defaultValue;
Jake Berger

1
@jberger "as"를 사용하여 값으로 캐스팅하는 것은 잠재적으로 bool과 같은 값을 반환 할 수 있으므로 제네릭 유형에 대한 클래스 제약이 없기 때문에 액세스 할 수 없습니다. @AlexFord 죄송 HttpSessionState합니다. 세션 을 연장하고 싶습니다 . :)
리처드

과연. Richard가 언급했듯이 제약이 필요합니다. (... 그리고 다른 방법은 값 유형을 사용하려는 경우)
제이크 버거

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

예, 이것은 의도 된 문제에 대한보다 일반적인 대답입니다.-당신은 나를 이겼고-안전한 탐색을위한 후보자입니다 (간단한 일에 대해 람다가 마음에 들지 않는다면)-그러나 여전히 작성하기가 약간 번거 롭습니다. 음 :). 개인적으로 저는 항상? : 대신 (비싸지 않다면, 어쨌든 재 배열한다면) ...
NSGaga-mostly-inactive

... 그리고 '이름 지정'은 이것의 진짜 문제입니다. 어떤 것도 제대로 묘사하는 것 (또는 너무 많이 '추가')하거나 길지 않습니다. have ?? still)- '재산'또는 '안전'이 내가 사용한 것입니다. value.Dot (o => o.property) ?? @default 어쩌면?
NSGaga-mostly-inactive

@NSGaga : 우리는 꽤 오랫동안 이름을왔다 갔다했습니다. 우리는 고려 Dot했지만 너무 설명 적이 지 않다는 것을 알았습니다. 우리 NullOr는 자기 설명과 간결함 사이의 좋은 절충안으로 정착했습니다 . 이름 지정에 대해 전혀 신경 쓰지 않았다면 항상이라고 부를 수 _있습니다. 람다를 작성하기가 너무 번거 롭다면 스 니펫을 사용해도되지만 개인적으로는 충분히 쉽습니다. 에 관해서? : 더 복잡한 표현식에서는 사용할 수 없으며 새 로컬로 이동해야합니다. NullOr그것을 피할 수 있습니다.
Timwi

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;

3

보조 기능 생성

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


string y = GetValue( 'key', 'none' );

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


null defaultValue필요하지 않은 경우 예외를 throw하는 이유는 무엇입니까 (즉 input != null)?
Attila

input != null평가는 그 자체로 객체를 반환합니다. input == null매개 변수로 제공된 문자열을 반환합니다. 그러므로 부를 수 가능하면 사람입니다 .OnNullAsString(null)-하지만 (드물게 유용한 확장 방법이기는하지만) 목적은 당신도 객체 등이나 기본 문자열 ... 결코 null를 얻을 수 있도록했다
one.beat.consumer

input!=null경우 시나리오에만 입력을 반환 defaultValue!=null도 가지고있다; 그렇지 않으면 ArgumentNullException.
Attila

0

이것은?를 지원하지 않는 .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);
    }
}

첫 번째 인수는 테스트 된 개체입니다. 두 번째는 기능입니다. 세 번째는 null 값입니다. 따라서 귀하의 경우 :

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

nullable 유형에도 매우 유용합니다. 예를 들면 :

decimal? v;
...
IsNull.Substitute(v,v.Value,0);
....
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.