?? 빈 문자열에 대한 병합?


165

내가 점점 더 많이하고있는 것은 문자열이 비어 있거나 (있는 ""또는 null 인) 조건부 연산자를 확인하는 것입니다.

현재 예 :

s.SiteNumber.IsNullOrEmpty() ? "No Number" : s.SiteNumber;

이것은 확장 방법 일 뿐이며 다음과 같습니다.

string.IsNullOrEmpty(s.SiteNumber) ? "No Number" : s.SiteNumber;

비어 있고 null ??이 아니기 때문에 트릭을 수행하지 않습니다. 의 string.IsNullOrEmpty()버전은 ??완벽한 솔루션이 될 것입니다. 나는 이것을하는 더 깨끗한 방법이 있어야한다고 생각하지만 (나는 희망한다!), 나는 그것을 찾지 못했습니다.

.Net 4.0에만있는 사람 이라도이 작업을 수행하는 더 좋은 방법을 알고 있습니까?


11
약간의 감탄을주기 위해 F #에서 사용자 정의 임시 바이너리 (및 해당 단항) 연산자를 쉽게 정의 할 수 있습니다. 여기 let (|?) x y = if String.IsNullOrEmpty(x) then y else x와 같이 사용하십시오 s.SiteNumber |? "No Number".
— Stephen Swensen

답변:


72

이를위한 기본 제공 방법은 없습니다. 그러나 확장 메소드가 문자열 또는 널을 리턴하도록하여 통합 연산자가 작동 할 수 있습니다. 그러나 이것은 이상 할 것입니다. 개인적으로 귀하의 현재 접근 방식을 선호합니다.

이미 확장 메서드를 사용하고 있으므로 값이나 기본값을 반환하는 확장 메서드를 만드는 것이 어떻습니까?

string result = s.SiteNumber.ConvertNullOrEmptyTo("No Number");

7
나는 당신이 옳다고 생각하며, 이것은 여전히 ​​읽을 수있는 가장 깨끗한 솔루션입니다. ???그래도 C # 5 의 연산자 와 같은 것을 알고 싶습니다 .
— Nick Craver

2
그리고 무엇입니까 ??? 운영자? null 외에도 기본값을 사용합니까? 매우 복잡하게 들린다
— bevacqua

1
람다 식으로? 예를 들어 : "항목"이 널 입력 가능하다고 가정하면 ... item ?? x=> x.ToString() : null;
— Isaac Llopis

@IsaacLlopis 그 영업의 원래 조각보다 더 찾고 지저분한 - 어 끝
— maksymiuk

133

C #은 이미 우리가 값을 대체 할 수 있습니다 null로 ??. 따라서 빈 문자열을로 변환하는 확장명 만 있으면 null다음과 같이 사용합니다.

s.SiteNumber.NullIfEmpty() ?? "No Number";

확장 클래스 :

public static class StringExtensions
{
    public static string NullIfEmpty(this string s)
    {
        return string.IsNullOrEmpty(s) ? null : s;
    }
    public static string NullIfWhiteSpace(this string s)
    {
        return string.IsNullOrWhiteSpace(s) ? null : s;
    }
}

44

나는 이것이 오래된 질문이라는 것을 알고 있지만 대답을 찾고 있었고 위의 어느 것도 내 필요와 내가 사용한 것을 충족시키지 못했습니다.

private static string Coalesce(params string[] strings)
{
    return strings.FirstOrDefault(s => !string.IsNullOrEmpty(s));
}

용법:

string result = Coalesce(s.SiteNumber, s.AltSiteNumber, "No Number");

편집 : 이 함수를 작성하는 훨씬 간단한 방법은 다음과 같습니다.

static string Coalesce(params string[] strings) => strings.FirstOrDefault(s => !string.IsNullOrEmpty(s));

1
나는 좋아하지만 컴파일러 오류를 수정하고 좀 더 작게 만들어야했습니다.
— gregmac

이 Coalesce를 사용하여 값을 가져 오지 않고 왜 비어 있지 않은 값을 선택해야합니까? 혼란스러운 이름의 친구입니다.
— Jimmyt1988

8
Coalesce는 많은 데이터베이스에서 동일한 작업을 수행하기 위해 사용되는 용어이므로 (널이 아닌 값을 먼저 찾습니다) 문자열을 결합하면 연결됩니다.
— 카메론 포워드

최고의 답변using System.Linq
— JoePC

우아하고 훌륭합니다.
— 마리아노 루이스 빌라

16

사용하고 싶은 몇 가지 유틸리티 확장이 있습니다.

public static string OrDefault(this string str, string @default = default(string))
{
    return string.IsNullOrEmpty(str) ? @default : str;
}

public static object OrDefault(this string str, object @default)
{
    return string.IsNullOrEmpty(str) ? @default : str;
}

편집 : sfsr 의 답변에서 영감을 얻어 지금부터 도구 상자 에이 변형을 추가 할 것입니다.

public static string Coalesce(this string str, params string[] strings)
{
    return (new[] {str})
        .Concat(strings)
        .FirstOrDefault(s => !string.IsNullOrEmpty(s));
}

1
"Coalesce"라는 용어를 사용했지만 null 통합 연산자 (??)의 의도와 더 유사하기 때문에 "Coalesce"라는 용어를 사용하고 있습니다.
— llaughlin

매개 변수 의 @접두사 는 무엇을 @default합니까? 나는 전에 그것을 본 적이 없다.
— Drew Chapin

3
@druciferre- defaultC #에서 예약 키워드이지만 변수 이름 으로 사용할 수 있습니다 .
— Justin Morgan

1
@ Jimmyt1988-표준 T-SQL COALESCE 함수 와 비슷하기 때문 입니다.
— Justin Morgan

1
@ Jimmyt1988-또한 임의 길이 목록에서 비어 있지 않은 첫 번째 기능을 구체적으로 선택하기 때문 입니다. 미묘한 세부 사항이지만 T-SQL 함수는 동일한 방식으로 작동합니다. 이름은 문서의 유무에 관계없이 해당 기능을 아는 사람에게 직관적입니다.
— Justin Morgan

6

이전에 제안 된 것보다 약간 빠른 확장 방법 :

public static string Fallback(this string @this, string @default = "")
{
    return (@this == null || @this.Trim().Length == 0) ? @default : @this;
}

11
자르고 길이를 지정하는 대신 IsNullOrWhitespace 를 사용하지 않겠습니까 ?
— weston December

1
code공개 정적 문자열 Coalesce (이 문자열 @this, 문자열 @default = "") {return (@this == null || String.IsNullOrWhiteSpace (@this))? @default : @this; }
— paul-2011

6

널 병합 연산자의 장점 중 하나는 단락되는 것입니다. 첫 번째 부분이 null이 아닌 경우 두 번째 부분은 평가되지 않습니다. 폴백에 값 비싼 작업이 필요한 경우에 유용 할 수 있습니다.

나는 결국 :

public static string Coalesce(this string s, Func<string> func)
{
    return String.IsNullOrEmpty(s) ? func() : s;
}

용법:

string navigationTitle = model?.NavigationTitle.
    Coalesce(() => RemoteTitleLookup(model?.ID)). // Expensive!
    Coalesce(() => model?.DisplayName);

6

문자열이 비어 있으면 항상 null을 반환하는 NullIfEmpty 확장 메서드를 사용하면됩니다. (Null Coalescing Operator)가 정상적으로 사용됩니다.

public static string NullIfEmpty(this string s)
{
    return s.IsNullOrEmpty() ? null : s;
}

그러면 허용됩니다 ?? 정상적으로 사용되며 체인을 쉽게 읽을 수 있습니다.

string string1 = string2.NullIfEmpty() ?? string3.NullIfEmpty() ?? string4;

3

문자열 확장 메서드 ValueOrDefault ()는 어떻습니까

public static string ValueOrDefault(this string s, string sDefault)
{
    if (string.IsNullOrEmpty(s))
        return sDefault;
    return s;
}

문자열이 비어 있으면 null을 반환합니다.

public static string Value(this string s)
{
    if (string.IsNullOrEmpty(s))
        return null;
    return s;
}

그래도 이러한 솔루션을 시도하지 않았습니다.


2
나는 옵션 # 1을 좋아하지만 Or ()와 같은 의미 론적이라고 부를 수는 있지만 "string s = s.SiteNumber.Or ("Default ");"
— jvenema

2
...OrDefault()프레임 워크의 나머지 ...OrDefault()메소드 처럼 동작하지 않으면 무언가를 호출하는 것이 혼란 스러울 수 있습니다 . 그렇 든 없든 MS는 사용자 지정 메서드에서 해당 동작을 명명하고 이탈하는 것이 API 사용자에게 불필요하게 혼동된다는 특별한 의미를 부여했습니다.
— mattmc3

3

내 자신의 문자열 Coalesce 확장 방법을 사용하고 있습니다. 여기에있는 사람들은 LINQ를 사용하고 시간 집약적 인 작업을 위해 리소스를 낭비하고 있기 때문에 (나는 그것을 꽉 찬 루프에서 사용하고 있습니다) 공유 할 것입니다.

public static class StringCoalesceExtension
{
    public static string Coalesce(this string s1, string s2)
    {
        return string.IsNullOrWhiteSpace(s1) ? s2 : s1;
    }
}

나는 그것이 매우 간단하다고 생각하며 null 문자열 값을 신경 쓰지 않아도됩니다. 다음과 같이 사용하십시오.

string s1 = null;
string s2 = "";
string s3 = "loudenvier";
string s = s1.Coalesce(s2.Coalesce(s3));
Assert.AreEqual("loudenvier", s);

나는 그것을 많이 사용합니다. "유틸리티"기능 중 하나는 먼저 사용하지 않고는 살 수 없습니다 :-)


나는 그들이 LINQ를 사용하는 이유를 이해하지 못한다고 생각하며, 매개 변수가 호출 전에 평가되므로 s2.Coalesce(s3)필요하지 않은 경우에도 실행됩니다. NullIfEmpty()확장 프로그램 을 사용하는 것이 좋습니다 ??.
— NetMage

@NetMage LINQ 버전이 내가 제시 한 것보다 성능이 훨씬 떨어진다는 것을 보증 할 수 있습니다. 원하는 경우 간단한 벤치 마크를 만들어이를 테스트 할 수 있습니다. 벤치마킹 코드를 작성할 때 일반적인 함정을 피하기 위해 github.com/dotnet/BenchmarkDotNet 을 사용하는 것이 좋습니다 .
— Loudenvier

0

QQQ물론 다음과 같은 확장 방법의 간결함이 마음에 듭니다 . 더 좋을 것입니다. 그러나 두 개뿐 아니라 세 개의 문자열 옵션 값을 비교할 수 있으므로 1을 처리 할 수 ​​있습니다.

#region QQ

[DebuggerStepThrough]
public static string QQQ(this string str, string value2)
{
    return (str != null && str.Length > 0)
        ? str
        : value2;
}

[DebuggerStepThrough]
public static string QQQ(this string str, string value2, string value3)
{
    return (str != null && str.Length > 0)
        ? str
        : (value2 != null && value2.Length > 0)
            ? value2
            : value3;
}


// Following is only two QQ, just checks null, but allows more than 1 string unlike ?? can do:

[DebuggerStepThrough]
public static string QQ(this string str, string value2, string value3)
{
    return (str != null)
        ? str
        : (value2 != null)
            ? value2
            : value3;
}

#endregion

짧은 이름을 좋아한다면이라고 부를 수 있으며 다른 답변과 마찬가지로 키워드를 Or사용하여 params여러 매개 변수에 대한 중복 정의를 피할 수 있습니다.
— Chiel ten Brinke

아이디어 주셔서 감사합니다. 그 후 오랫동안이 이름을 "FirstNotNull"로 바꿨습니다. 에 params, 그것으로, 기본 시나리오 이틀 동안 그렇게하지 않는 것이 좋습니다 것입니다 params만 기본 하나 또는 두 개의 입력이있을 때 불필요하게 할당 할 수 배열됩니다. 그 후 의미가 있습니다.
— Nicholas Petersen
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.