Cách thực hành tốt nhất để sử dụng các loại tham chiếu Nullable cho DTOs


20

Tôi có một DTO được điền bằng cách đọc từ bảng DynamoDB. Nói rằng nó trông như thế này hiện tại:

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
}

Có thực hành tốt nhất phát triển để đối phó với điều này? Tôi muốn tránh một nhà xây dựng không tham số vì nó chơi không tốt với ORM trong SDK Động (cũng như các công cụ khác).

Nó có vẻ lạ đối với tôi để viết public string Id { get; set; } = "";bởi vì điều này sẽ không bao giờ xảy ra vì Idlà một PK và không bao giờ có thể là null. Việc sử dụng sẽ ""là gì ngay cả khi nó bằng cách nào đó?

Vì vậy, bất kỳ thực hành tốt nhất về điều này?

  • Tôi có nên đánh dấu tất cả chúng string?để nói rằng chúng có thể là null mặc dù một số không bao giờ nên như vậy.
  • Tôi có nên khởi IdNamevới ""vì họ nên không bao giờ được null và chương trình này mục đích cho dù ""sẽ không bao giờ được sử dụng.
  • Một số kết hợp ở trên

Xin lưu ý: đây là về loại tham chiếu vô hiệu C # 8 Nếu bạn không biết những gì tốt nhất không trả lời.


Nó hơi bẩn, nhưng bạn chỉ có thể tát #pragma warning disable CS8618vào đầu tập tin.
Hai mươi hai

7
Thay vào đó = "", bạn có thể sử dụng = null!để khởi tạo một thuộc tính mà bạn biết sẽ không bao giờ có hiệu quả null(khi trình biên dịch không có cách nào để biết điều đó). Nếu Descriptioncó thể hợp pháp null, nó nên được khai báo a string?. Ngoài ra, nếu việc kiểm tra tính không hợp lệ đối với DTO gây nhiều phiền toái hơn là trợ giúp, bạn chỉ có thể bọc loại trong #nullable disable/ #nullable restoređể tắt NRT cho loại này.
Jeroen Mostert

@JeroenMostert Bạn nên đặt nó làm câu trả lời.
Magnus

3
@Magnus: Tôi miễn cưỡng trả lời bất kỳ câu hỏi nào yêu cầu "thực hành tốt nhất"; những điều như vậy là rộng và chủ quan. Tôi hy vọng OP có thể sử dụng nhận xét của tôi để phát triển "thực tiễn tốt nhất" của riêng họ.
Jeroen Mostert

1
@ IvanGarcíaTopete: Mặc dù tôi đồng ý rằng việc sử dụng chuỗi cho khóa chính là không bình thường và thậm chí có thể không phù hợp tùy thuộc vào hoàn cảnh, lựa chọn loại dữ liệu của OP không liên quan đến câu hỏi. Điều này có thể dễ dàng áp dụng cho một thuộc tính chuỗi được yêu cầu, không có giá trị không phải là khóa chính hoặc thậm chí là một trường chuỗi là một phần của khóa chính tổng hợp và câu hỏi vẫn còn tồn tại.
Jeremy Caney

Câu trả lời:


12

Như một tùy chọn, bạn có thể sử dụng defaultkết hợp với nghĩa đennull forgiving operator

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

Vì DTO của bạn được điền từ DynamoDB, bạn có thể sử dụng MaybeNull/NotNull các thuộc tính postcondition để kiểm soát tính không hợp lệ

  • MaybeNull Giá trị trả về không nullable có thể là null.
  • NotNull Giá trị trả về nullable sẽ không bao giờ là null.

Nhưng các thuộc tính này chỉ ảnh hưởng đến phân tích nullable cho người gọi của các thành viên được chú thích với họ. Thông thường, bạn áp dụng các thuộc tính này cho các phương thức trả về phương thức, thuộc tính và bộ chỉ mục.

Vì vậy, bạn có thể xem xét tất cả các thuộc tính của mình là không thể rỗng và trang trí chúng bằng MaybeNullthuộc tính, cho biết chúng trả về nullgiá trị có thể

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

Ví dụ sau đây cho thấy việc sử dụng Itemlớp cập nhật . Như bạn có thể thấy, dòng thứ hai không hiển thị cảnh báo, nhưng dòng thứ ba thì không

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.

Hoặc bạn có thể biến tất cả các thuộc tính thành không thể và sử dụng NoNullđể biểu thị giá trị trả về không thể null( Idví dụ)

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

Cảnh báo sẽ giống với ví dụ trước.

Ngoài ra còn có AllowNull/DisallowNull các thuộc tính điều kiện tiên quyết cho các tham số đầu vào, thuộc tính và chỉ mục setters, làm việc theo cách tương tự.

  • AllowNull Một đối số đầu vào không nullable có thể là null.
  • DisallowNull Một đối số đầu vào nullable không bao giờ nên null.

Tôi không nghĩ rằng nó sẽ giúp bạn, vì lớp của bạn được điền từ cơ sở dữ liệu, nhưng bạn có thể sử dụng chúng để kiểm soát tính vô hiệu của setters thuộc tính, như thế này cho tùy chọn đầu tiên

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

Và cho cái thứ hai

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

Một số chi tiết hữu ích và ví dụ về bài đăng / điều kiện tiên quyết có thể được tìm thấy trong bài viết devblog này


6

Câu trả lời của sách giáo khoa trong kịch bản này là sử dụng một thuộc tính string?của bạn Id, nhưng cũng trang trí nó với [NotNull]thuộc tính:

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

Tham khảo: Theo tài liệu , [NotNull]thuộc tính "chỉ định rằng một đầu ra không phải là null ngay cả khi loại tương ứng cho phép nó."

Vì vậy, những gì chính xác đang xảy ra ở đây?

  1. Thứ nhất, string?kiểu trả về ngăn chặn các trình biên dịch từ cảnh báo bạn rằng bất động sản chưa được định hình trong quá trình thi và do đó sẽ mặc định để null.
  2. Sau đó, [NotNull]thuộc tính ngăn cảnh báo khi gán thuộc tính cho biến không có giá trị hoặc cố gắng hủy đăng ký vì bạn đang thông báo cho phân tích dòng tĩnh của trình biên dịch rằng, trong thực tế , thuộc tính này sẽ không bao giờ null.

Cảnh báo: Như với tất cả các trường hợp liên quan đến bối cảnh vô hiệu của C #, về mặt kỹ thuật, không có gì ngăn bạn trả lại nullgiá trị ở đây và do đó, có khả năng, đưa ra một số ngoại lệ xuôi dòng; tức là, không có xác nhận thời gian chạy ngoài hộp. Tất cả C # từng cung cấp là một cảnh báo trình biên dịch. Khi bạn giới thiệu, [NotNull]bạn đang ghi đè lên cảnh báo đó một cách hiệu quả bằng cách đưa ra gợi ý về logic kinh doanh của bạn. Như vậy, khi bạn chú thích một tài sản với [NotNull], bạn phải chịu trách nhiệm cho cam kết của mình rằng "điều này sẽ không bao giờ xảy ra vì Idlà PK và không bao giờ có thể là null".

Để giúp bạn duy trì cam kết đó, bạn có thể bổ sung muốn chú thích bất động sản với các [DisallowNull]thuộc tính:

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

Tham khảo: Theo tài liệu , [DisallowNull]thuộc tính "chỉ định không nullđược phép làm đầu vào ngay cả khi loại tương ứng cho phép."

Điều này có thể không phù hợp trong trường hợp của bạn vì những giá trị đang được giao thông qua cơ sở dữ liệu, nhưng [DisallowNull]thuộc tính sẽ cung cấp cho bạn một cảnh báo nếu bạn đã bao giờ cố gắng gán một nullgiá trị (có thể) để Id, mặc dù kiểu trả về khác cho phép nó được rỗng . Về mặt đó, Idsẽ hành động chính xác như stringliên quan đến phân tích dòng tĩnh của C #, đồng thời cho phép giá trị vẫn chưa được xác định giữa việc xây dựng đối tượng và dân số của tài sản.

Lưu ý: Như những người khác đã đề cập, bạn cũng có thể đạt được một kết quả hầu như giống hệt bằng cách gán các Idgiá trị mặc định của một trong hai default!hoặc null!. Đây là, một phần của một sở thích phong cách. Tôi thích sử dụng các chú thích vô hiệu vì chúng rõ ràng hơn và cung cấp kiểm soát chi tiết, trong khi đó dễ dàng lạm dụng !như một cách tắt trình biên dịch. Hoàn toàn khởi tạo một tài sản có giá trị cũng làm tôi khó chịu nếu tôi biết rằng tôi sẽ không bao giờ sử dụng giá trị đó ngay cả khi đó là mặc định.


-2

Chuỗi là một loại tham chiếu và luôn luôn là null, bạn không cần phải làm gì đặc biệt. Bạn chỉ có thể gặp sự cố sau này nếu bạn muốn ánh xạ loại đối tượng này sang loại đối tượng khác, nhưng bạn có thể xử lý vấn đề đó sau.


8
Anh ta đang nói về các loại tham chiếu Nullable trong C # 8
Magnus
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.