2017-11-21 62 views
1

:이 언어 기능 이유를 더 잘 이해 얻으려고 노력

을 우리는 가지고 :

public static DateTime? Date { get; set; } 


static void Main(string[] args) 
{ 
    Date = new DateTime(2017, 5, 5); 

    Console.WriteLine(Date.Value.Date); 
    Console.Read(); 
} 

이 왜 값을 사용하여 다음을해야합니까 nullable 형식에서 값을 가져 오겠습니까? Date를 호출하기 전에 null을 검사하는 것과 같지 않습니다. 값이 null 인 경우 NullReference 예외가 발생합니다. 나는 이유를 알았습니다 .HasValue는 작동 할 수 있습니다.

왜 우리가 필요한지 확신 할 수 없습니다. 각 nulllable 유형에 값이 있습니까?

+0

어, 값을 어떻게 읽을 수 있습니까? – maccettura

+0

그 대신에 무엇을 제안합니까? – Servy

+0

왜 객체에 직접 점을 찍을 수 없습니까? –

답변

4

null 입력 가능 유형이 구현 된 방식 때문입니다.

questionmark 구문은 …? 구문이이 유형의 언어 기능인 경우를 제외하고는 자신을 잘 쓸 수있는 구조체 인 Nullable<T>으로 변환됩니다.

Nullable<T>의 .NET 핵심 구현은 오픈 소스이며 its code은이를 설명하는 데 도움이됩니다. 당신이 DateTime aDateTime = (DateTime)nullableDateTime 같은 캐스트/임무를 수행 할 때

public readonly struct Nullable<T> where T : struct 
{ 
    private readonly bool hasValue; // Do not rename (binary serialization) 
    internal readonly T value; // Do not rename (binary serialization) 

    … 

    public T Value 
    { 
     get 
     { 
      if (!hasValue) 
      { 
       ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_NoValue); 
      } 
      return value; 
     } 
    } 
… 

하면, 당신은 연산자를 호출 .Value에 액세스 할 때

Nullable<T> 만 부울 필드와 기본 유형의 값 필드가 단지 예외가 발생합니다 이 클래스는 사용자 정의 유형에 정의 된 연산자와 똑같은 방식으로 작동하는 동일한 클래스에 정의됩니다. 이 연산자는 .Value 그래서 캐스트가 속성에 액세스 숨 깁니다 호출

public static explicit operator T(Nullable<T> value) 
    { 
     return value.Value; 
    } 

또한 역 할당 연산자가 있습니다를, 그래서 DateTime? nullableNow = DateTime.Now는 부를 것이다 :

public static implicit operator Nullable<T>(T value) 
    { 
     return new Nullable<T>(value); 
    } 
14

먼저의 질문을 명확히 할 수 있습니다.

C# 1.0에는 값 유형 (null이 아님)과 참조 유형 (null 입력 가능)의 두 가지 범주가있었습니다.

* 값과 참조 타입 모두 인스턴스와 연관된 값을 선택하는 부재 액세스 연산자, .을 지원한다.

참조 유형의 경우 . 연산자와 수신기의 null 허용 여부는 수신기가 null 참조 인 경우 . 연산자를 사용하면 예외가 발생합니다. C# 1.0 값 유형은 처음에는 nullable이 아니기 때문에 . null 값 유형 일 때 어떤 일이 발생하는지 지정할 필요가 없습니다. 그들은 존재하지 않는다.

C# 2.0에서는 null 값 유형이 추가되었습니다. Nullable 값 유형은 메모리 내 표시가 나타나는 한 마술 같은 것이 아닙니다. 값의 인스턴스가있는 구조체이고 null인지 아닌지를 나타내는 bool입니다.

nullable 값 유형이 리프팅 의미와 일치하므로 컴파일러 마법 (**)이 있습니다..리프팅 우리는 nullable 값 형식의 연산에 "값이 null이 아니고 값에 연산을 수행하고 결과를 Nullable 형식으로 변환합니다. 그렇지 않으면 결과가 null입니다"라는 의미를 가짐을 의미합니다. (***)

우리는 컴파일러가 효율적으로 해제 연산을 구현하는 마법의 모든 종류를하고있는 장면 뒤에

int? x = 2; 
int? y = 3; 
int? z = null; 
int? r = x + y; // nullable 5 
int? s = y + z; // null 

이있는 경우, 말을하는 것입니다

; see my lengthy blog series on how I wrote the optimizer if this subject interests you.

그러나 . 연산자는 이 아니며이 해제되었습니다. 그것은 수! 수신기가 null의 경우 예외를 던져, 또는

  • 그것은 널 (NULL) 연산처럼 행동 수 :

    1. nullable.Whatever()이 같은 널 (NULL) 참조 형식으로 동작 할 수 않습니다이 이해하기 적어도 두 가지 디자인은 nullable가 null의 경우 Whatever()에 대한 호출이 생략되고 결과는 Whatever()이 반환 한 모든 유형의 null입니다.

    그래서 질문은 : 합리적인 디자인 그냥 작동 및 기본 유형의 멤버를 추출하는 . 운영자가있을 때

    .Value.을 필요로?

    음.

    내가 방금 한 일에 주목하십시오. 두 가지 가능성이 모두 완벽하게 이해되며 언어의 확립되고 잘 이해 된 측면과 일치하며 서로 상반됩니다. 언어 디자이너들은 항상 의 지팡이에 자신을 발견합니다.. nullable 값 형식의 .이 참조 형식에서 .처럼 동작해야하는지 또는 .이 nullable int에 +처럼 동작해야하는지 여부는 완전히 알 수없는 상황에 처해 있습니다. 둘 다 그럴듯 해. 어느 것이 든 집어 들었을 때 누군가가 잘못되었다고 생각할 것입니다.

    언어 디자인 팀에서는 명시 적으로 지정하는 등의 대안을 고려했습니다. 예를 들어, "Elvis"?. 연산자는 명시 적으로 null 값으로 올릴 수있는 멤버 액세스 권한입니다. 이것은 C# 2.0에서 고려되었지만 거부되었고 결국 C# 6.0에 추가되었습니다. 고려 된 몇 가지 다른 통사론 적 해결책이 있었지만 모두 역사적으로 손실 된 이유로 거부당했습니다.

    이미 값 유형에 .에 대한 잠재적 인 설계 지뢰밭이 있지만 대기 상태가 악화됨을 알았습니다. 값 형식에 적용 할 때

    하는의 지금 .의 또 다른 측면을 살펴 보자 : 값 유형이 끔찍한 가변 값 유형이며, 회원이 필드 경우, 다음 x.y변수x 경우입니다 변수이고, 그렇지 않으면 값입니다. 즉, x이 변수 인 경우 x.y = 123이 유효합니다.그러나 x이 변수가 아니면 값이 사본에 지정되므로 C# 컴파일러는 할당을 허용하지 않습니다.

    이 값은 nullable 값 유형과 어떤 관련이 있습니까? nullable 변경할 수있는 값 유형이있는 경우

    x.y = 123 
    

    할 수 있습니까? x 정말 불변 유형 Nullable<X>의 인스턴스이기 때문에이 x.Value.y = 123 다음 을 의미한다면 우리는 매우, 매우 잘못된 것 같습니다 Value 재산에 의해 반환되는 값의 복사본을 돌연변이있다 기억하십시오.

    그럼 어떻게해야합니까? nullable 값 유형을 스스로 변경할 수 있어야합니까? 그 돌연변이는 어떻게 작동할까요? copy-in-copy-out 의미론입니까? 이는 ref이 속성이 아니라 변수를 요구하기 때문에 ref x.y이 불법이라는 것을 의미합니다.

    거대한 freakin '엉망 될 수 있습니다.

    C# 2.0에서는 디자인 팀이 제네릭을 언어에 추가하려고 시도했습니다. 기존 유형 시스템에 제네릭을 추가하려고 시도한 적이 있다면 얼마나 많은 작업인지 알 수 있습니다. 그렇지 않다면, 그것은 많은 일을합니다. 디자인 팀은이 모든 문제에 대해 펀트를 결정할 수있는 패스를 부여 받아 .에 nullable 값 유형에 특별한 의미가 없다고 생각합니다. "가치를 원한다면 .Value이라고 부릅니다."디자인 팀 측에서는 특별한 작업이 필요 없다는 이점이 있습니다! 그리고 비슷하게, "가변적 인 nullable 값 유형을 사용하는 것이 상처라면, 아마도 그 일을 그만 두십시오"라는 것은 디자이너에게는 저렴한 비용입니다.


    우리가 다음 우리는 두 C# 1.0 유형의 직교가지했을 것이다 완벽한 세계에 살고있는 경우 : nullable이 아닌 유형의 대 값 형식에 대 참조 유형 및 nullable 형식을. 우리가 얻은 것은 nullable 참조 형식과 C# 1.0의 nullable 값 형식, C# 2.0의 nullable 값 형식 및 10 년 반 후 C# 8.0의 nullaable 참조 형식입니다.

    완벽한 세계에서 우리는 모든 연산자 의미론, 의미 지우기, 변수 의미론 등을 정렬하여 을 모두 한 번에으로 일관되게 만듭니다.

    하지만 우리는 완벽한 세상에 살지 않습니다. 우리는 완벽한 것이 적의 적이며, C# 2.0에서 5.0까지는 . 대신에 .Value., C# 6.0에서는 ?. 대신에 .Value.을 써야합니다.


    * 나는 의도적으로 널 (NULL)과 값 형식의 일부 특성과 참조 타입의 몇 가지 특성을 가지고 있고, 역 참조 및 멤버 액세스에 대한 자신의 특별한 연산자를 가지고있는 포인터 유형을 무시하고있다.

    ** nullable 값 형식은 값 형식 제약 조건, nullable 값 형식 상자를 null 참조 또는 boxed 기본 형식 및 기타 많은 작은 특수 동작을 수행하지 않는 것과 같은 항목에 마법이 있습니다. 그러나 메모리 레이아웃은 불가사의 한 것은 아닙니다. 그것은 단지 bool 옆에있는 값입니다.

    *** 기능 프로그래머는 물론 모나드의 바인드 작업임을 알고 있습니다.

  • +1

    오, 내 블로그는 좋아하지만, 그렇습니다. 감사! – VMAtm