[C#] 문자열 유형의 기본값이 빈 문자열 대신 널인 이유는 무엇입니까?

등의 null메소드를 안전하게 적용하기 전에 모든 문자열을 테스트하는 것은 상당히 성가신 ToUpper()일입니다 StartWith().

기본값이 경우 string빈 문자열 있었다, 나는 시험이없는 것, 그리고 내가 좋아하는 다른 값 유형과 일관성을 위해 그것을 느낄 것 int또는 double예를 들어. 또한 Nullable<String>의미가 있습니다.

그렇다면 C # 디자이너 null가 문자열의 기본값 으로 사용하기 로 선택한 이유는 무엇입니까?

참고 : 이것은 이 질문 과 관련 있지만 질문 과 관련하여 대신에 이유에 더 중점을 둡니다.



답변

문자열 유형의 기본값이 빈 문자열 대신 널인 이유는 무엇입니까?

때문에 stringA는 참조 형 과 기본 값은 모든 참조 형식입니다 null.

ToUpper (), StartWith () 등과 같은 메소드를 안전하게 적용하기 전에 모든 문자열을 null로 테스트하는 것은 상당히 성가신 일입니다.

이는 참조 유형의 동작과 일치합니다. 인스턴스 멤버를 호출하기 전에 null 참조를 확인해야합니다.

string의 기본값이 빈 문자열이라면 테스트 할 필요가 없으며 int 또는 double과 같은 다른 값 유형과 더 일관성이 있다고 생각합니다.

이외의 특정 참조 유형 기본값 지정 null은 할 것 일관성을 .

또한 Nullable<String>의미가 있습니다.

Nullable<T>값 유형과 함께 작동합니다. 참고로 사실이다 Nullable원본에 소개되지 않은 .NET 플랫폼 깨진 코드를 많이들이 그 규칙을 변경했다가되었을 것이다, 그래서이. ( 의례의 @jcolebrand )


답변

하비브가 옳습니다. string . 참조 유형 입니다.

그러나 더 중요한 것은 사용할 때마다 확인할 필요가 없습니다null . ArgumentNullException누군가가 함수를 전달하면 아마도null 참조를 .

여기에 문제 NullReferenceException가 있습니다. 어쨌든 .ToUpper()문자열 을 호출하려고하면 프레임 워크가 대신 합니다. null매개 변수가 평가 될 수 있으므로 함수에 전달 된 객체의 속성이나 메서드는 인수를 테스트하더라도이 경우가 여전히 발생할 수 있습니다.null .

존재가 말했다, 빈 문자열 또는 null을 확인하는 것이 할 수있는 일반적인 일이, 그들이 제공하는 그래서 String.IsNullOrEmpty()String.IsNullOrWhiteSpace()단지 이러한 목적을 위해.


답변

확장 방법을 작성할 수 있습니다 (가치있는 것).

public static string EmptyNull(this string str)
{
    return str ?? "";
}

이제 이것은 안전하게 작동합니다.

string str = null;
string upper = str.EmptyNull().ToUpper();


답변

C # 6.0에서 다음을 사용할 수도 있습니다.

string myString = null;
string result = myString?.ToUpper();

문자열 결과는 null입니다.


답변

빈 문자열과 null은 근본적으로 다릅니다. null은 값이없고 빈 문자열은 비어있는 값입니다.

변수의 “값”에 대해 가정하는 프로그래밍 언어 (이 경우 빈 문자열)는 null 참조 문제를 일으키지 않는 다른 값으로 문자열을 시작하는 것만 큼 좋습니다.

또한 해당 문자열 변수의 핸들을 응용 프로그램의 다른 부분으로 전달하면 의도적으로 빈 값을 전달했는지 또는 해당 변수의 값을 채우는 것을 잊었는지 여부를 해당 코드에서 확인할 방법이 없습니다.

이것이 문제가되는 또 다른 경우는 문자열이 일부 함수의 반환 값 인 경우입니다. string은 참조 유형이며 기술적으로 값이 null이고 비어있는 값을 가질 수 있으므로 함수는 기술적으로 null 또는 비어있는 값을 리턴 할 수 있습니다 (그렇게하는 것을 막을 방법은 없습니다). 이제 “값 없음”이라는 두 가지 개념, 즉 빈 문자열과 null이 있으므로이 함수를 사용하는 모든 코드는 2 개의 검사를 수행해야합니다. 하나는 비어 있고 다른 하나는 널입니다.

간단히 말해, 단일 상태에 대해 항상 하나의 표현 만 갖는 것이 좋습니다. 빈 및 널에 대한보다 자세한 내용은 아래 링크를 참조하십시오.

/software/32578/sql-empty-string-vs-null-value

사용자 입력을 처리 할 때 NULL 대 비어 있음


답변

근본적인 이유 / 문제는 CLS 사양의 디자이너 (언어가 .net과 상호 작용하는 방법을 정의)가 클래스 멤버가 callvirt호출자가 널 참조 검사; 또한 “정상적인”복싱에 적용되지 않는 구조를 정의하는 의미도 제공하지 않았습니다.

CLS 사양에 이러한 수단이 정의되어 있으면 .net이 COM (Common Object Model)에 의해 설정된 리드를 지속적으로 따르는 것이 가능합니다. 마찬가지로 기본값을 정의하기 위해 값 의미론을 가져야하는 사용자 정의 불변 클래스 유형. 기본적으로, 어떤의 각 구성원이 될 것 일어날 것 String예를 들면 것은, Length같은과 같이 작성한다 [InvokableOnNull()] int String Length { get { if (this==null) return 0; else return _Length;} }. 이 접근법은 가치처럼 행동 해야하는 것들에 대해 매우 훌륭한 의미를 제공했지만 구현 문제 때문에 힙에 저장해야합니다. 이 접근 방식의 가장 큰 어려움은 이러한 유형 간의 변환 의미론이 Object약간 어둡습니다.

다른 접근 방식은 상속하지 않고 Object대신 사용자 정의 boxing 및 unboxing 작업을 수행 하는 특수 구조 유형의 정의를 허용하는 것이 었습니다 (다른 클래스 유형으로 /에서 변환). 이러한 접근 방식에서는 NullableString문자열처럼 작동 하는 클래스 유형 과 String단일 개인 필드 Value유형을 보유하는 사용자 정의 상자 구조 유형 이 있습니다 String. 변환 시도 중StringNullableString또는 Object반환 Valuenull이 아닌 경우, 또는 String.Empty경우는 null입니다. 로 캐스팅하려고 String하면 NullableString인스턴스에 대한 null이 아닌 참조 는 참조를 Value저장합니다 (길이가 0 인 경우 null을 저장함). 다른 참조를 캐스팅하면 예외가 발생합니다.

문자열을 힙에 저장해야하지만 널이 아닌 기본값을 가진 값 유형처럼 작동 하지 않아야 하는 이유는 개념적으로 없습니다 . 참조를 보유한 “정상”구조로 저장하면 “문자열”유형으로 사용하는 코드에서 효율적일 수 있지만 “객체”로 캐스팅 할 때 간접적이고 비효율적 인 계층이 추가됩니다. 이 늦은 날짜에 위의 기능 중 하나를 추가하는 .net을 예측하지는 않지만 미래 프레임 워크의 디자이너는이 기능을 포함하는 것을 고려할 수 있습니다.


답변

문자열 변수는 인스턴스 가 아니라 참조 이기 때문 입니다.

기본적으로 비어 있음으로 초기화하는 것이 가능했지만 보드 전체에 많은 불일치가 발생했습니다.