DTO에 Nullable Reference Type을 사용하는 모범 사례


20

DynamoDB 테이블에서 읽어서 채워지는 DTO가 있습니다. 현재 다음과 같이 가정하십시오.

public class Item
{
    public string Id { get; set; } // PK so technically cannot be null
    public string Name { get; set; } // validation to prevent nulls but this doesn't stop database hacks
    public string Description { get; set; } // can be null
}

이를 처리하기 위해 개발할 모범 사례가 있습니까? 매개 변수가없는 생성자는 Dynamo SDK의 ORM (및 기타)에서 제대로 작동하지 않기 때문에 오히려 매개 변수가없는 생성자를 피하고 싶습니다.

PK public string Id { get; set; } = "";이기 때문에 결코 발생 Id하지 않으며 결코 null 이 될 수 없기 때문에 글을 쓰는 것이 이상하게 보입니다 . ""어쨌든 어떻게 되었더라도 어떤 용도로 사용 됩니까?

이에 대한 모범 사례는 무엇입니까?

  • 그들 string?중 일부는 결코 없어야하지만 null이 될 수 있다고 말해야합니다.
  • 나는 초기화해야 IdName함께 ""그들이 있기 때문에 해야 널 (null)이 쇼 결코 의도는 비록 ""사용되지 않을 것입니다.
  • 위의 일부 조합

참고 : 이것은 C # 8 nullable 참조 유형 에 관한 것입니다.


조금 더럽지 만 #pragma warning disable CS8618파일 상단에서 때릴 수 있습니다 .
20에서

7
보다는 = "", 당신은 사용할 수 있습니다 = null!효과적으로 없을 것 알고 속성 초기화 null(컴파일러가를 알 수있는 방법이 없을 때)을. Description합법적으로 할 수 있으면 null로 선언해야합니다 string?. 또는 DTO에 대한 Null 허용 여부 확인이 도움말보다 성가신 경우 유형을 #nullable disable/ #nullable restore로 감싸서이 유형에 대해서만 NRT를 해제 할 수 있습니다 .
Jeroen Mostert

@JeroenMostert 당신은 대답으로 넣어야합니다.
Magnus

3
@ Magnus : 저는 "모범 사례"를 요구하는 질문에 대답하기를 꺼려합니다. 그러한 것들은 광범위하고 주관적입니다. OP가 내 의견을 사용하여 자체 '모범 사례'를 개발할 수 있기를 바랍니다.
Jeroen Mostert

1
@ IvanGarcíaTopete : 기본 키에 문자열을 사용하는 것은 드문 일이며 상황에 따라 바람직하지 않을 수도 있지만 OP의 데이터 유형 선택은 질문과 관련이 없습니다. 이것은 기본 키가 아닌 null이 아닌 필수 문자열 속성이나 복합 기본 키의 일부인 문자열 필드에도 쉽게 적용될 수 있으며 여전히 문제가 있습니다.
Jeremy Caney

답변:


12

옵션으로 default리터럴을null forgiving operator

public class Item
{
    public string Id { get; set; } = default!;
    public string Name { get; set; } = default!;
    public string Description { get; set; } = default!;
}

DTO가 DynamoDB에서 채워 지므로 MaybeNull/NotNull 사후 조건 속성 을 사용하여 null 가능성을 제어 할 수 있습니다

  • MaybeNull 널 입력 불가능 리턴 값은 널일 수 있습니다.
  • NotNull nullable 반환 값은 null이되지 않습니다.

그러나 이러한 특성은 주석이 달린 구성원의 발신자에 대한 Null 허용 분석에만 영향을줍니다. 일반적으로 이러한 속성을 메서드 반환, 속성 및 인덱서 게터에 적용합니다.

따라서 모든 속성을 null이 아닌 속성으로 간주하고 MaybeNull속성으로 장식하여 가능한 null값을 반환 함을 나타낼 수 있습니다

public class Item
{
    public string Id { get; set; } = "";
    [MaybeNull] public string Name { get; set; } = default!;
    [MaybeNull] public string Description { get; set; } = default!;
}

다음 예제는 업데이트 된 Item클래스 의 사용법을 보여줍니다 . 보시다시피, 두 번째 줄에는 경고가 표시되지 않지만 세 번째 줄에는 경고가 표시됩니다

var item = new Item();
string id = item.Id;
string name = item.Name; //warning CS8600: Converting null literal or possible null value to non-nullable type.

또는 모든 속성을 nullable 속성으로 만들고 NoNull반환 값을 표시 할 수 없습니다 null( Id예 :).

public class Item
{
    [NotNull] public string? Id { get; set; }
    public string? Name { get; set; }
    public string? Description { get; set; }
}

경고는 이전 예제와 동일합니다.

입력 매개 변수, 속성 및 인덱서 세터에 대한 AllowNull/DisallowNull 사전 조건 특성 도 비슷한 방식으로 작동합니다.

  • AllowNull 널 입력 불가능 입력 인수는 널일 수 있습니다.
  • DisallowNull 널 입력 가능 인수는 널이 아니어야합니다.

클래스가 데이터베이스에서 채워지기 때문에 도움이 될 것이라고 생각하지 않지만 첫 번째 옵션에서 이와 같이 속성 설정 기의 Null 허용 여부를 제어하는 ​​데 사용할 수 있습니다

[MaybeNull, AllowNull] public string Description { get; set; }

그리고 두 번째

[NotNull, DisallowNull] public string? Id { get; set; }

post / preconditions에 대한 몇 가지 유용한 세부 사항과 예제는이 devblog 기사 에서 찾을 수 있습니다.


6

이 시나리오의 교과서 대답은을 사용하는 것입니다 string?당신을 위해 Id재산, 그러나 또한 로 장식 [NotNull]속성 :

public class Item
{
  [NotNull] public string? Id { get; set; }
  public string Name { get; set; }
  public string? Description { get; set; }
}

참조 : 에 따른 문서[NotNull]속성 "이 출력되지 않도록 지정은 대응하는 형태가 허용하는 경우에도 널 (null)."

그래서 여기서 정확히 무슨 일이 일어나고 있습니까?

  1. 첫째, string?반환 유형은 생성 중에 속성이 초기화되지 않았다는 컴파일러의 경고를 표시하지 않으므로 기본값 은로 설정 됩니다 null.
  2. 그런 다음 [NotNull]속성을 null이 아닌 변수에 속성을 할당하거나 참조를 해제하려고 할 때 경고를 방지합니다 . 실제로 컴파일러의 정적 흐름 분석 에 실제로이 속성은 절대로 적용되지 않습니다 null.

경고 : C #의 Null 허용 컨텍스트와 관련된 모든 경우와 마찬가지로 기술적으로 여전히 null값을 반환하지 못하게 하여 다운 스트림 예외가 발생할 가능성이 없습니다. 즉, 즉시 사용 가능한 런타임 유효성 검사가 없습니다. 모든 C #은 컴파일러 경고입니다. 소개 [NotNull]할 때 비즈니스 로직에 대한 힌트를 제공하여 경고를 효과적으로 무시합니다. 이와 같이, 당신이 가진 속성에 주석을 때 [NotNull], 당신은 당신의 약속에 대한 책임을 복용 "이 것 결코 부터 발생하지 IdPK가하고 null이 될 수 없다을."

이러한 약속을 유지하기 위해 속성에 속성에 주석을 추가 할 수 있습니다 [DisallowNull].

public class Item
{
  [NotNull, DisallowNull] public string? Id { get; set; }
  public string Name { get; set; }
  public string? Description { get; set; }
}

참조 : 에 따른 문서[DisallowNull]속성 "지정 null입력으로 허용되고 대응하는 유형을 허용하더라도."

값이 데이터베이스를 통해 할당되고 있기 때문에 이것은 귀하의 경우와 관련없는,하지만 [DisallowNull]혹시 대입 할 때 속성은 당신에게 경고를 줄 것이다 null에 (수) 값을 Id, 이 수의 반환 형식은 달리 할 수에도 불구하고 널 (null) . 이와 관련하여, Id작용 것이다 정확히 유사한 string반면, C #까지의 정적 흐름 분석뿐만 우려 같은 값이 대상의 구조와 특성 사이의 인구 초기화되지 않은 상태를 유지하도록 허용한다.

참고 : 다른 사람들이 언급했듯이 Id기본값 default!또는 중 하나를 기본값 으로 지정하면 사실상 동일한 결과를 얻을 수 있습니다 null!. 이것은 분명히 문체 선호도입니다. 더 명확하고 세부적인 제어 기능을 제공하기 때문에 Null 허용 주석을 사용하는 것을 선호하지만 !컴파일러를 종료하는 방법으로 남용하기 쉽습니다 . 값을 사용하여 속성을 명시 적으로 초기화하면 해당 값을 기본값으로 사용하지 않더라도 절대 사용하지 않을 것입니다.


-2

문자열은 참조 유형이며 항상 nullable이므로 특별한 작업을 수행 할 필요가 없습니다. 이 객체 유형을 다른 객체 유형에 매핑하려는 경우 나중에 문제가 발생할 수 있지만 나중에 처리 할 수 ​​있습니다.


8
그는 C # 8에서 Nullable 참조 유형 에 대해 이야기하고 있습니다 .
Magnus
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.